package com.chenfan.mcn.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.utils.DateUtils;
import com.chenfan.common.utils.NumToChineseRMB;
import com.chenfan.common.vo.UserVO;
import com.chenfan.mcn.clients.finance.ClearData4ExecuteOrderVo;
import com.chenfan.mcn.constant.*;
import com.chenfan.common.extension.util.SmartCompletableFuture;
import com.chenfan.mcn.model.vo.ExcutionOrderBatchSubmitVO;
import com.chenfan.mcn.exception.RepeatedDataExeception;
import com.chenfan.mcn.extension.excel.ExcelCustom;
import com.chenfan.mcn.clients.baseinfo.*;
import com.chenfan.mcn.clients.finance.FinanceClient;
import com.chenfan.mcn.clients.finance.McnChargeCommonVO;
import com.chenfan.mcn.clients.privilege.*;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.dao.*;
import com.chenfan.mcn.enums.*;
import com.chenfan.mcn.event.EventPublisher;
import com.chenfan.mcn.event.OperateLogEvent;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.common.extension.dict.DictStream;
import com.chenfan.common.extension.dict.DictTranslationUtils;
import com.chenfan.mcn.extension.excel.ExcelUtils;
import com.chenfan.mcn.component.CodeGenerateHelper;
import com.chenfan.common.extension.lock.DistributedLockTemplate;
import com.chenfan.mcn.model.*;
import com.chenfan.mcn.model.common.KVPair;
import com.chenfan.mcn.model.dto.*;
import com.chenfan.mcn.model.rpc.*;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.mq.producer.ExcutionOrderMessageProducer;
import com.chenfan.mcn.service.*;
import com.chenfan.mcn.service.helper.CommonHelper;
import com.chenfan.mcn.utils.*;
import com.chenfan.process.client.ProcessClient;
import com.chenfan.process.dto.ApprovalOperationDTO;
import com.chenfan.process.enums.EventTypeEnums;
import com.chenfan.process.vo.ApprovalNodeVO;
import com.chenfan.process.vo.ApprovalOperationVO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author tangwei
 * Date:     2021/1/20 11:01
 * Description: 合同执行单
 */
@SuppressWarnings({"deprecation", "AlibabaUndefineMagicConstant", "AlibabaRemoveCommentedCode", "AlibabaMethodTooLong"})
@Slf4j
@Service
public class ContractExcutionOrderServiceImpl implements ContractExcutionOrderService, ApprovalCallbackService {

    private static final String SEPARATOR = "！";

    private static final String FINANCE_APPROVAL = "财务审核";

    /**
     * 主题 redis key
     */
    private static final String REDIS_KEY_KOC_IMPORT = "koc_import:";

    private static final String BUSINESS_BATCH = "koc_batch_excution_order:";

    /**
     * 批量导入
     */
    private static final long REDIS_KEY_KOC_IMPORT_BATCH_IMPORT_SIZE = 100 * 1024 * 1024;

    @Autowired
    private ContractExcutionOrderMapper contractExcutionOrderMapper;

    @Autowired
    private StarPlatformInfoService starPlatformInfoService;

    @Autowired
    private ExcuteFeedbackMapper excuteFeedbackMapper;

    @Autowired
    private CalculationDevidedMapper calculationDevidedMapper;

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Autowired
    private DiscountApprovalMapper discountApprovalMapper;

    @Autowired
    private StarAccountInfoService starAccountInfoService;

    @Autowired
    private DiscountApprovalService discountApprovalService;

    @Autowired
    private PlatformDiscountRangeService platformDiscountRangeService;

    @Autowired
    private ExcutionOrderMessageProducer excutionOrderMessageProducer;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private FinanceClient financeClient;

    @Autowired
    private ApprovalFlowService approvalFlowService;

    @Autowired
    private AnnualRebateApprovalMapper annualRebateApprovalMapper;

    @Autowired
    private IncomeContractService incomeContractService;

    @Autowired
    private IncomeContactAgreementMapper incomeContactAgreementMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ProcessClient processClient;

    @Autowired
    private YearFrameContractMapper yearFrameContractMapper;

    @Autowired
    private PurchaseContractMapper purchaseContractMapper;

    @Autowired
    private StarBillingHeaderMapper starBillingHeaderMapper;

    @Autowired
    private StarBasicDataMapper starBasicDataMapper;

    @Autowired
    private StarMonthlySettlementService settlementService;

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    @Autowired
    private StarAccountInfoMapper starAccountInfoMapper;

    @Autowired
    private MessageInfoService messageInfoService;

    @Autowired
    private StarMonthlySettlementDetailMapper starMonthlySettlementDetailMapper;

    @Autowired
    private DocIntentionOrderMapper intentionOrderMapper;

    @Autowired
    private DocIntentionOrderService docIntentionOrderService;

    @Autowired
    private StarPlatformInfoMapper starPlatformInfoMapper;

    @Autowired
    private OrderPlatformInfoMapper orderPlatformInfoMapper;

    @Autowired
    private BillAssociationDetailMapper billAssociationDetailMapper;

    @Autowired
    private StarContractDetailMapper starContractDetailMapper;

    @Autowired
    private BrandInfoService brandInfoService;

    @Autowired
    private CommonHelper commonHelper;

    @Override
    public void batchSave(List<ContractExcutionOrder> excutionOrders, IncomeContractAgreement incomeContractAgreement, IncomeContract incomeContract) {
        if (CollectionUtil.isNotEmpty(excutionOrders)) {
            Long customerId = incomeContract.getCustomerId();
            Map<Long, BaseCustomer> customerMap = baseInfoClient.getMcnCustomerByIds(Arrays.asList(customerId)).getObj();

            //查询执行单红人信息
            List<Long> starIds = excutionOrders.stream().map(x->x.getStarId()).collect(Collectors.toList());
            List<StarBasicData> starBasicDataList= starBasicDataMapper.selectBatchIds(starIds);
            Map<Long, StarBasicData> starBasicDataMap = starBasicDataList.stream().collect(Collectors.toMap(StarBasicData::getId, x -> x, (x, y) -> x));

            /**
             * 将执行单集合分组
             */
            List<ContractExcutionOrder> updateList = new ArrayList<>();
            List<ExcuteFeedback> feedbackInsertList = new ArrayList<>();
            List<CalculationDevided> calculationDevidedInsertList = new ArrayList<>();
            for (ContractExcutionOrder excutionOrder : excutionOrders) {
                if (excutionOrder.getId() == null) {
                    excutionOrder.setExcuteCode(CodeGenerateHelper.getCode(BillCodeCst.EXCUTION_ORDER));
                    excutionOrder.setContractAgreementId(incomeContractAgreement.getId());
                    excutionOrder.setIncomeContractId(incomeContractAgreement.getIncomeContractId());
                    excutionOrder.setIncomeContractCode(incomeContractAgreement.getIncomeContractCode());
                    excutionOrder.setApprovalStatus(ExcutionApprovalStatusEnum.UN_EXECUTE.getCode());
                    StarBasicData starBasicData = starBasicDataMap.get(excutionOrder.getStarId());
                    if (Objects.nonNull(starBasicData)) {
                        if (StarTypeEnum.INSIDE.getCode().equals(starBasicData.getStarType())) {
                            excutionOrder.setType(ExcutionOrderTypeEnum.INSIDE_EXCUTION_ORDER.getType());
                        } else if (StarTypeEnum.OUTSIDE.getCode().equals(starBasicData.getStarType())) {
                            excutionOrder.setType(ExcutionOrderTypeEnum.OUTSIDE_EXCUTION_ORDER.getType());
                        } else if (StarTypeEnum.KOC.getCode().equals(starBasicData.getStarType())) {
                            excutionOrder.setType(ExcutionOrderTypeEnum.KOC_EXCUTION_ORDER.getType());
                        }
                    }
                    contractExcutionOrderMapper.insert(excutionOrder);
                    incomeContractService.saveFeedBack(excutionOrder, feedbackInsertList);
                    //初始化计算分成的客户返点比例、年度返点比例、客户返点金额
                    CalculationDevided calculationDevided = new CalculationDevided();

                    incomeContractService.saveCalculationDevided(customerId, incomeContract.getDiscountId(), calculationDevided, customerMap, excutionOrder);
                    calculationDevidedInsertList.add(calculationDevided);
                } else {
                    CalculationDevided calculationDevided = calculationDevidedMapper.selectOne(Wrappers.lambdaQuery(CalculationDevided.class).eq(CalculationDevided::getExcutionOrderId, excutionOrder.getId()));
                    incomeContractService.saveCalculationDevided(customerId, incomeContract.getDiscountId(), calculationDevided, customerMap, excutionOrder);
                    calculationDevidedMapper.updateById(calculationDevided);
                    updateList.add(excutionOrder);
                }
                if(Objects.nonNull(excutionOrder.getIntentionOrderId())) {
                    //更新意向单绑定关系
                    DocIntentionOrder docIntentionOrder = new DocIntentionOrder();
                    docIntentionOrder.setIncomeContractId(incomeContract.getId());
                    docIntentionOrder.setIncomeContractCode(incomeContract.getContractCode());
                    docIntentionOrder.setExcutionOrderId(excutionOrder.getId());
                    docIntentionOrder.setExcutionOrderCode(excutionOrder.getExcuteCode());
                    docIntentionOrder.setPublishDate(excutionOrder.getPromisePublishDate());
                    docIntentionOrder.setPublishDateEnd(excutionOrder.getPromisePublishDateEnd());
                    docIntentionOrder.setId(excutionOrder.getIntentionOrderId());
                    intentionOrderMapper.updateById(docIntentionOrder);
                }
            }
            /**
             * 新增
             */
            if (CollectionUtil.isNotEmpty(feedbackInsertList)) {
                excuteFeedbackMapper.insertBatch(feedbackInsertList);
            }
            if (CollectionUtil.isNotEmpty(calculationDevidedInsertList)) {
                calculationDevidedMapper.insertBatch(calculationDevidedInsertList);
            }
            /**
             * 修改
             */
            if (CollectionUtil.isNotEmpty(updateList)) {
                List<Long> excutionOrderIds = updateList.stream().map(ContractExcutionOrder::getId).filter(Objects::nonNull).collect(Collectors.toList());
                Map<Long, ContractExcutionOrder> beforeMap = CommonUtil.defaultList(contractExcutionOrderMapper.selectBatchIds(excutionOrderIds)).stream()
                        .collect(Collectors.toMap(ContractExcutionOrder::getId, Function.identity()));
                updateList.forEach(contractExcutionOrder -> contractExcutionOrderMapper.updateById(contractExcutionOrder));
                Map<Long, ContractExcutionOrder> afterMap = CommonUtil.defaultList(contractExcutionOrderMapper.selectBatchIds(excutionOrderIds)).stream()
                        .collect(Collectors.toMap(ContractExcutionOrder::getId, Function.identity()));
                for(Long excutionOrderId : excutionOrderIds) {
                    if(CommonUtil.containsKey(beforeMap, excutionOrderId)) {
                        EventPublisher.post(OperateLogEvent.builder().businessId(excutionOrderId)
                                .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                                .compare(beforeMap.get(excutionOrderId), afterMap.get(excutionOrderId)).build());
                    }
                }
            }
        }
    }

    @Override
    public List<BasicExcutionOrderVO> basicExcutionOrderList(List<ContractExcutionOrder> excutionOrders) {
        if(CollectionUtils.isEmpty(excutionOrders)) {
            return new ArrayList<>(0);
        }
        /**
         * 查询红人信息
         */
        List<Long> platInfoIds = excutionOrders.stream().map(ContractExcutionOrder::getStarPlatformInfoId).collect(Collectors.toList());
        List<StarPlatInfoVO> starPlatInfoVOList = starPlatformInfoService.getByIds(platInfoIds);
        Map<Long, StarPlatInfoVO> starPlatInfoVoMap = starPlatInfoVOList.stream().collect(Collectors.toMap(StarPlatInfoVO::getId, starPlatInfoVO -> starPlatInfoVO));
        Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.PUBLISHING_PLATFORM);
        List<String> brandCodes = excutionOrders.stream().map(ContractExcutionOrder::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
        List<BasicExcutionOrderVO> excutionOrdersVOList = excutionOrders.stream().map(e -> {
            BasicExcutionOrderVO basicExcutionOrderVO = new BasicExcutionOrderVO();
            BeanUtils.copyProperties(e, basicExcutionOrderVO);
            if (CommonUtil.containsKey(starPlatInfoVoMap, basicExcutionOrderVO.getStarPlatformInfoId())) {
                StarPlatInfoVO starPlatInfoVO = starPlatInfoVoMap.get(basicExcutionOrderVO.getStarPlatformInfoId());
                basicExcutionOrderVO.setStarId(starPlatInfoVO.getStarId());
                basicExcutionOrderVO.setStarNickName(starPlatInfoVO.getPlatNickName());
                basicExcutionOrderVO.setPlatformName(starPlatInfoVO.getPlatformName());
                basicExcutionOrderVO.setStarRealName(starPlatInfoVO.getStarRealName());
                basicExcutionOrderVO.setPlatformId(starPlatInfoVO.getPlatformId());
                basicExcutionOrderVO.setPlatNickName(starPlatInfoVO.getPlatNickName());
                basicExcutionOrderVO.setPublishFormName(CommonUtil.getMapValue(secondlevelDictMap.get(basicExcutionOrderVO.getPlatformId()), basicExcutionOrderVO.getPublishForm()));
            }
            if(brandMap.containsKey(basicExcutionOrderVO.getBrandName())) {
                basicExcutionOrderVO.setBrandNameN(brandMap.get(basicExcutionOrderVO.getBrandName()));
            }
            basicExcutionOrderVO.setApprovalStatusName(ExcutionApprovalStatusEnum.getStatusName(basicExcutionOrderVO.getApprovalStatus()));
            return basicExcutionOrderVO;
        }).collect(Collectors.toList());
        //字典翻译
        DictTranslationUtils.translation(() -> DictStream.of(
                DictStream.map(DictTypeCst.FORMAL_CONTRACT, BasicExcutionOrderVO::getOrderPlatform, BasicExcutionOrderVO::setOrderPlatformName),
                DictStream.map(DictTypeCst.RELEASE_TYPE, BasicExcutionOrderVO::getPublishType, BasicExcutionOrderVO::setPublishTypeName),
                DictStream.map(DictTypeCst.BRAND_CATEGORY, BasicExcutionOrderVO::getCategory, BasicExcutionOrderVO::setCategoryName)
                ),(dictProfileList, dictList) -> Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                        .setDictsCodes(dictList.stream().distinct().collect(Collectors.toList())).setProfileCodes(dictProfileList))).getObj(),
                excutionOrdersVOList
        );
        return excutionOrdersVOList;
    }

    @Override
    public PaidInfoDetailVO detailPaidInfoOfCode(String excuteCode) {
        ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectOne(Wrappers.<ContractExcutionOrder>lambdaQuery().eq(ContractExcutionOrder::getExcuteCode, excuteCode));
        BusinessAssert.notNull(contractExcutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        PaidInfoDetailVO paidInfoDetailVO = new PaidInfoDetailVO();
        paidInfoDetailVO.setPaidDate(contractExcutionOrder.getPaidStarDate());
        paidInfoDetailVO.setRemark(contractExcutionOrder.getPaidRemark());
        paidInfoDetailVO.setAccountId(contractExcutionOrder.getAccountId());
        paidInfoDetailVO.setAccountType(contractExcutionOrder.getAccountType());
        paidInfoDetailVO.setHandlingFeeRate(contractExcutionOrder.getHandlingFeeRate());
        // 查询计算分成
        CalculationDevided calculationDevided = calculationDevidedMapper.selectOne(Wrappers.lambdaQuery(CalculationDevided.class)
                .eq(CalculationDevided::getExcutionOrderId, contractExcutionOrder.getId()));
        if (calculationDevided != null) {
            paidInfoDetailVO.setFinanceDevidedAmount(calculationDevided.getFinanceDevidedAmount());
            if(Objects.nonNull(contractExcutionOrder.getHandlingFeeRate()) && Objects.nonNull(calculationDevided.getFinanceDevidedAmount())) {
                paidInfoDetailVO.setHandlingFeeAmount(calculationDevided.getFinanceDevidedAmount()
                        .multiply(contractExcutionOrder.getHandlingFeeRate().divide(McnConstant.ONE_HUNDRED))
                        .divide(BigDecimal.ONE.add(contractExcutionOrder.getHandlingFeeRate().divide(McnConstant.ONE_HUNDRED)), 2, BigDecimal.ROUND_HALF_UP));
            }
        }
        paidInfoDetailVO.setCustomerInvoiceWay(contractExcutionOrder.getCustomerInvoiceWay());
        paidInfoDetailVO.setPaidWay(contractExcutionOrder.getPaidWay());
        return paidInfoDetailVO;
    }

    @Override
    public ExcutionOrderDetailVO detail(Long id) {
        ExcutionOrderDetailVO excutionOrderDetailVO = new ExcutionOrderDetailVO();
        ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectOne(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getId, id).eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(contractExcutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        BeanUtils.copyProperties(contractExcutionOrder, excutionOrderDetailVO);
        excutionOrderDetailVO.setPaybackStatusName(PaybackStatusEnum.getStatusName(contractExcutionOrder.getPaybackStatus()));
        excutionOrderDetailVO.setCommissionSettleStatusName(CommonSettleStatusEnum.getStatusName(contractExcutionOrder.getCommissionSettleStatus()));
        excutionOrderDetailVO.setBusinessCommissionSettleStatusName(CommonSettleStatusEnum.getStatusName(contractExcutionOrder.getBusinessCommissionSettleStatus()));
        excutionOrderDetailVO.setRebateSettleStatusName(CommonSettleStatusEnum.getStatusName(contractExcutionOrder.getRebateSettleStatus()));
        Long processId = ApprovalEnum.getEnumByExcutionOrderType(contractExcutionOrder.getType()).getProcessId();
        Long flowId = approvalFlowService.getFlowId(contractExcutionOrder.getId(), processId);
        String stringFlowIds = approvalFlowService.getStringFlowIds(contractExcutionOrder.getId(), processId);
        excutionOrderDetailVO.setFlowId(flowId);
        excutionOrderDetailVO.setFlowIds(stringFlowIds);
        List<Long> flowList = new ArrayList<>(Collections.singletonList(flowId));
        JSONObject flowMapping = approvalFlowService.getFlowStatus(flowList);
        if (Objects.nonNull(flowMapping)) {
            if (flowMapping.size() > 0 && Objects.nonNull(excutionOrderDetailVO.getFlowId())) {
                excutionOrderDetailVO.setFlowStatusName(flowMapping.getString(excutionOrderDetailVO.getFlowId().toString()));
            }
        }
        //查询红人及平台基本信息
        starPlatInfoVO(excutionOrderDetailVO, contractExcutionOrder);
        // 查询执行反馈
        ExcuteFeedback excuteFeedback = excuteFeedbackMapper.selectOne(Wrappers.lambdaQuery(ExcuteFeedback.class).eq(ExcuteFeedback::getExcutionOrderId, id));
        // 查询收入合同
        IncomeContract incomeContract = incomeContractService.selectById(contractExcutionOrder.getIncomeContractId());
        BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
        ExcutionOrderContractVO excutionOrderContractVO = new ExcutionOrderContractVO();
        BeanUtils.copyProperties(incomeContract, excutionOrderContractVO);
        Long contractProcessId = ApprovalEnum.getEnumByContractType(incomeContract.getContractType()).getProcessId();
        incomeContractData(incomeContract, excutionOrderContractVO, contractProcessId);
        //红人开票抬头数据
        if (Objects.nonNull(contractExcutionOrder.getStarBillingHeaderId())) {
            StarBillingHeader billingHeader = starBillingHeaderMapper.selectOne(Wrappers.lambdaQuery(StarBillingHeader.class).eq(StarBillingHeader::getId, contractExcutionOrder.getStarBillingHeaderId()));
            excutionOrderDetailVO.setStarBillingHeader(billingHeader);
        } else {
            excutionOrderDetailVO.setStarBillingHeader(new StarBillingHeader());
        }
        // 查询客户档案
        List<Long> customerIds = new ArrayList<>();
        customerIds.add(incomeContract.getCustomerId());
        if(Objects.nonNull(contractExcutionOrder.getCustomerId())){
            customerIds.add(contractExcutionOrder.getCustomerId());
        }
        Map<Long, BaseCustomer> baseCustomerMap = baseInfoClient.getMcnCustomerByIds(customerIds).getObj();
        CustomerVO customerVO = new CustomerVO();
        BaseCustomer baseCustomer = baseCustomerMap.get(incomeContract.getCustomerId());
        if (Objects.nonNull(baseCustomer)) {
            BeanUtils.copyProperties(baseCustomer, customerVO);
            customerVO.setCustomerState(baseCustomer.getCustomerState());
            excutionOrderDetailVO.setFixedRebateRatio(baseCustomer.getFixedRebateRatio());
        }
        if (Objects.nonNull(contractExcutionOrder.getCustomerId())) {
            BaseCustomer baseCustomerContract = baseCustomerMap.get(contractExcutionOrder.getCustomerId());
            if (Objects.nonNull(baseCustomerContract)) {
                excutionOrderDetailVO.setCustomerName(baseCustomerContract.getCustomerNameC());
            }
        }
        //查詢打款信息和计算分成相关代码
        StarAccountInfo starAccountInfo = paidInfoDetailData(contractExcutionOrder, excutionOrderDetailVO, id, customerVO);
        //查询执行人&收入合同&客户档案创建人所属部门
        fillDepartmentInfo(excutionOrderDetailVO, contractExcutionOrder, incomeContract, excutionOrderContractVO, customerVO, baseCustomer);
        // 查询执行单对应的账单流程ID
        List<McnChargeCommonVO> chargeList = CommonUtil.defaultList(financeClient.getMcnCharge(excutionOrderDetailVO.getExcuteCode()).getObj())
                .stream().filter(e -> !NumberCst.FIVE.equals(e.getCheckStatus())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(chargeList)) {
            excutionOrderDetailVO.setInvoiceFlowId(chargeList.get(0).getInvoiceFlowId());
            excutionOrderDetailVO.setInvoiceFlowIds(chargeList.get(0).getInvoiceFlowIds());
        }
        //红人月度结算
        StarMonthlySettlement starMonthlySettlement = settlementService.getSettlementByExcuteId(id);
        if (Objects.nonNull(starMonthlySettlement)) {
            excutionOrderDetailVO.setStarSettlementId(starMonthlySettlement.getId());
            excutionOrderDetailVO.setStarSettlementCode(starMonthlySettlement.getSettlementCode());
        }
        DocIntentionOrder docIntentionOrder = intentionOrderMapper.selectOne(Wrappers.lambdaQuery(DocIntentionOrder.class).eq(DocIntentionOrder::getExcutionOrderId, id));
        if(Objects.nonNull(docIntentionOrder)) {
            excutionOrderDetailVO.setIntentionId(docIntentionOrder.getId());
            excutionOrderDetailVO.setIntentionCode(docIntentionOrder.getIntentionCode());
            excutionOrderDetailVO.setIsLiveAd(docIntentionOrder.getIsLiveAd());
            excutionOrderDetailVO.setHaveDiscountApproval(docIntentionOrder.getHaveDiscountApproval());
            excutionOrderDetailVO.setDiscountScreenshot(docIntentionOrder.getDiscountScreenshot());
        }
        //查询客户返点合同编号
        List<BillAssociationDetail> billAssociationDetails = billAssociationDetailMapper.selectList(Wrappers.lambdaQuery(BillAssociationDetail.class)
                .select(BillAssociationDetail::getBillCode).eq(BillAssociationDetail::getBillType, NumberCst.ZERO).eq(BillAssociationDetail::getExcutionOrderId, id)
                .eq(BillAssociationDetail::getIsInvalid, NumberCst.ZERO).eq(BillAssociationDetail::getIsDelete, NumberCst.ZERO));
        if(CollectionUtils.isNotEmpty(billAssociationDetails)) {
            excutionOrderDetailVO.setRebateContractCode(billAssociationDetails.stream().map(BillAssociationDetail::getBillCode).distinct()
                    .collect(Collectors.joining(SeparatorCst.COMMA)));
        }
        // 填充数据字典值
        this.setDicts(excutionOrderDetailVO, excutionOrderContractVO, customerVO, starAccountInfo);
        excutionOrderDetailVO.setExcuteFeedback(excuteFeedback);
        excutionOrderDetailVO.setIncomeContract(excutionOrderContractVO);
        excutionOrderDetailVO.setCustomerVO(customerVO);
        excutionOrderDetailVO.setPlatformOrderNumber(excutionOrderDetailVO.getPlatformOrderCode());
        return excutionOrderDetailVO;
    }

    /**
     * 填充执行人&收入合同&客户档案创建人所属部门
     * @param excutionOrderDetailVO
     * @param contractExcutionOrder
     * @param incomeContract
     * @param excutionOrderContractVO
     * @param customerVO
     * @param baseCustomer
     */
    private void fillDepartmentInfo(ExcutionOrderDetailVO excutionOrderDetailVO, ContractExcutionOrder contractExcutionOrder, IncomeContract incomeContract, ExcutionOrderContractVO excutionOrderContractVO, CustomerVO customerVO, BaseCustomer baseCustomer) {
        // 查询执行人&收入合同&客户档案创建人所属部门
        List<Long> userIds = new ArrayList<>();
        userIds.add(contractExcutionOrder.getExcutorId());
        userIds.add(incomeContract.getCreateBy());
        if (Objects.nonNull(baseCustomer)) {
            userIds.add(baseCustomer.getCreateBy());
        }
        List<SUserVo> sUserVoList = privilegeClient.getDepartmentByUserIds(userIds).getObj();

        if (CollectionUtil.isNotEmpty(sUserVoList)) {
            // 设置收入合同&客户档案创建人所属部门
            Map<Long, SUserVo> sUserVoMap = sUserVoList.stream().collect(Collectors.toMap(SUserVo::getUserId, sUserVo -> sUserVo));
            if(CommonUtil.containsKey(sUserVoMap, contractExcutionOrder.getExcutorId())) {
                excutionOrderDetailVO.setExcutorDepartment(sUserVoMap.get(contractExcutionOrder.getExcutorId()).getDepartmentName());
            }
            if(CommonUtil.containsKey(sUserVoMap, excutionOrderContractVO.getCreateBy())) {
                excutionOrderContractVO.setDepartmentName(sUserVoMap.get(excutionOrderContractVO.getCreateBy()).getDepartmentName());
            }
            if(CommonUtil.containsKey(sUserVoMap, customerVO.getCreateBy())) {
                customerVO.setDepartmentName(sUserVoMap.get(customerVO.getCreateBy()).getDepartmentName());
            }
        }
        if(Objects.nonNull(contractExcutionOrder.getExcutorId())) {
            Map<Long, DepartmentVO> departmentVoMap = privilegeClient.getDepartmentHeadByUserIds(Arrays.asList(contractExcutionOrder.getExcutorId())).getObj();
            if(CommonUtil.containsKey(departmentVoMap, contractExcutionOrder.getExcutorId())) {
                DepartmentVO departmentVO = departmentVoMap.get(contractExcutionOrder.getExcutorId());
                excutionOrderDetailVO.setExcutorLeaderId(departmentVO.getDepartmentHeadId());
                excutionOrderDetailVO.setExcutorLeaderName(departmentVO.getDepartmentHeadName());
            }
        }
    }

    /**
     * 填充数据字典值
     * @param contractExcutionOrder 执行单表信息
     * @param incomeContract 收入合同信息
     * @param baseCustomer 基础档案信息
     * @param starAccountInfo 红人信息表
     * @param platformId 平台ID
     */
    private void setDicts(ExcutionOrderDetailVO contractExcutionOrder, ExcutionOrderContractVO incomeContract,
                          CustomerVO baseCustomer, StarAccountInfo starAccountInfo) {
        String platformId = contractExcutionOrder.getPlatformId();
        List<String> profileCodes = Arrays.asList("formal_contract", "SubjectOfContract", "Source_of_contract", "Release_type", "Release_form", "BrandCategory", "excute_difficulty", "Customer_classification",
                "Customer_source", "Brand_sales_channel", "Customer_status", "Customer_rating", "account_type");
        List<String> dicts = new ArrayList<>();
        dicts.add(contractExcutionOrder.getPublishType());
        dicts.add(contractExcutionOrder.getPublishForm());
        dicts.add(contractExcutionOrder.getCategory());
        if (StringUtils.isNotBlank(contractExcutionOrder.getOrderPlatform())) {
            dicts.add(contractExcutionOrder.getOrderPlatform());
        }
        if (incomeContract != null) {
            dicts.add(incomeContract.getFormalContractType());
            dicts.add(incomeContract.getCompanyContractSubject());
            dicts.add(incomeContract.getCooperateSource());
        }
        if (baseCustomer != null) {
            dicts.add(baseCustomer.getCustomerClassification());
            dicts.add(baseCustomer.getCustomerSource());
            dicts.add(baseCustomer.getBrandCategory());
            List<String> list = Arrays.asList(baseCustomer.getBrandDistributionChannel().split(","));
            dicts.addAll(list);
            dicts.add(baseCustomer.getCustomerState());
            dicts.add(baseCustomer.getCustomerScore());

        }
        if (starAccountInfo != null) {
            dicts.add(starAccountInfo.getAccountType());
        }
        /**
         * 查询并设置数据字典中文名称
         */
        DescByCodeDTO descByCodeDTO = new DescByCodeDTO();
        descByCodeDTO.setProfileCodes(profileCodes);
        descByCodeDTO.setDictsCodes(dicts);
        Map<String, String> dictsNameMap = baseInfoClient.getDescByCode(descByCodeDTO).getObj();

        //赋值平台名称 这个比较特殊 改字段了因此需要单独处理
        if(StringUtils.isNotBlank(contractExcutionOrder.getPublishForm())){
            Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.PUBLISHING_PLATFORM);
            contractExcutionOrder.setPublishFormName(CommonUtil.getMapValue(secondlevelDictMap.get(platformId), contractExcutionOrder.getPublishForm()));
        }
        //合作内容
        if(StringUtils.isNotBlank(contractExcutionOrder.getCooperationContent())){
            Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.ACTIVE_PLATFORMS);
            contractExcutionOrder.setCooperationContentName(CommonUtil.getMapValue(secondlevelDictMap.get(platformId), contractExcutionOrder.getCooperationContent()));
        }
        Map<String, String> brandMap = brandInfoService.getBrandMapByCodes(Lists.newArrayList(contractExcutionOrder.getBrandName(), incomeContract.getCooperateBrand()));
        contractExcutionOrder.setBrandNameN(brandMap.get(contractExcutionOrder.getBrandName()));

        contractExcutionOrder.setPublishType(dictsNameMap.get(DictTypeCst.RELEASE_TYPE+ ";" + contractExcutionOrder.getPublishType()));
        contractExcutionOrder.setCategory(dictsNameMap.get(DictTypeCst.BRAND_CATEGORY + ";" + contractExcutionOrder.getCategory()));
        //赋值下单平台名称
        if (StringUtils.isNotBlank(contractExcutionOrder.getOrderPlatform())) {
            contractExcutionOrder.setOrderPlatformName(dictsNameMap.get(DictTypeCst.FORMAL_CONTRACT + ";" + contractExcutionOrder.getOrderPlatform()));
        }
        if (incomeContract != null) {
            incomeContract.setFormalContractType(dictsNameMap.get(DictTypeCst.FORMAL_CONTRACT + ";" + incomeContract.getFormalContractType()));
            incomeContract.setCooperateSource(dictsNameMap.get(DictTypeCst.SOURCE_OF_CONTRACT + ";" + incomeContract.getCooperateSource()));
            incomeContract.setCooperateBrandName(brandMap.get(incomeContract.getCooperateBrand()));
        }
        if (baseCustomer != null) {
            baseCustomer.setCustomerClassificationName(dictsNameMap.get(DictTypeCst.CUSTOMER_CLASSIFICATION + ";" + baseCustomer.getCustomerClassification()));
            baseCustomer.setCustomerSource(dictsNameMap.get(DictTypeCst.CUSTOMER_SOURCE + ";" + baseCustomer.getCustomerSource()));
            baseCustomer.setBrandCategory(dictsNameMap.get(DictTypeCst.BRAND_CATEGORY + ";" + baseCustomer.getBrandCategory()));
            baseCustomer.setCustomerState(dictsNameMap.get(DictTypeCst.CUSTOMER_STATUS + ";" + baseCustomer.getCustomerState()));
            baseCustomer.setCustomerScore(dictsNameMap.get(DictTypeCst.CUSTOMER_RATING + ";" + baseCustomer.getCustomerScore()));
            List<String> classifications = new ArrayList<>();
            List<String> list = Arrays.asList(baseCustomer.getBrandDistributionChannel().split(","));
            if (CollectionUtils.isNotEmpty(list)) {
                list.forEach(c -> {
                    classifications.add(dictsNameMap.get(DictTypeCst.BRAND_SALES_CHANNEL + ";" + c));
                });
                baseCustomer.setBrandDistributionChannel(String.join(",", classifications));
            }
        }
        if (starAccountInfo != null) {
            starAccountInfo.setAccountType(dictsNameMap.get(DictTypeCst.ACCOUNT_TYPE + ";" + starAccountInfo.getAccountType()));
        }
    }


    /**
     * 查询红人基本信息
     */
    public void starPlatInfoVO(ExcutionOrderDetailVO excutionOrderDetailVO, ContractExcutionOrder contractExcutionOrder) {
        StarPlatInfoVO starPlatInfoVO = starPlatformInfoService.getById(contractExcutionOrder.getStarPlatformInfoId());
        BusinessAssert.notNull(starPlatInfoVO, McnErrorCode.STAR_PLATOFRM_INFO_IS_NULL);
        excutionOrderDetailVO.setStarId(starPlatInfoVO.getStarId());
        excutionOrderDetailVO.setStarNickName(starPlatInfoVO.getStarNickname());
        excutionOrderDetailVO.setStarRealName(starPlatInfoVO.getStarRealName());
        excutionOrderDetailVO.setStarAgentId(starPlatInfoVO.getStarAgentId());
        excutionOrderDetailVO.setStarAgentName(starPlatInfoVO.getStarAgentName());
        excutionOrderDetailVO.setPlatformId(starPlatInfoVO.getPlatformId());
        excutionOrderDetailVO.setPlatformName(starPlatInfoVO.getPlatformName());
        excutionOrderDetailVO.setPlatNickName(starPlatInfoVO.getPlatNickName());
        excutionOrderDetailVO.setStarDevidedRate(starPlatInfoVO.getDevidedRate());
        excutionOrderDetailVO.setIsAllPlatform(starPlatInfoVO.getIsAllPlatform());
    }


    /**
     * 查詢打款信息
     */
    public StarAccountInfo paidInfoDetailData(ContractExcutionOrder contractExcutionOrder, ExcutionOrderDetailVO excutionOrderDetailVO, Long id, CustomerVO customerVO) {
        /**
         * 查詢打款信息
         */
        PaidInfoDetailVO paidInfoDetailVO = new PaidInfoDetailVO();
        paidInfoDetailVO.setPaidDate(contractExcutionOrder.getPaidStarDate());
        paidInfoDetailVO.setRemark(contractExcutionOrder.getPaidRemark());
        paidInfoDetailVO.setAccountId(contractExcutionOrder.getAccountId());
        paidInfoDetailVO.setAccountType(contractExcutionOrder.getAccountType());
        paidInfoDetailVO.setHandlingFeeRate(contractExcutionOrder.getHandlingFeeRate());
        paidInfoDetailVO.setCustomerInvoiceWay(contractExcutionOrder.getCustomerInvoiceWay());
        paidInfoDetailVO.setPaidWay(contractExcutionOrder.getPaidWay());
        // 查询红人账户信息
        StarAccountInfo starAccountInfo = new StarAccountInfo();
        if (contractExcutionOrder.getStarAccountInfoId() != null) {
            starAccountInfo = starAccountInfoService.getById(contractExcutionOrder.getStarAccountInfoId());
            paidInfoDetailVO.setTaxRate(starAccountInfo.getTaxRate());
            excutionOrderDetailVO.setStarAccountInfoId(starAccountInfo.getId());
        }
        // 查询计算分成
        CalculationDevided calculationDevided = calculationDevidedMapper.selectOne(Wrappers.lambdaQuery(CalculationDevided.class)
                .eq(CalculationDevided::getExcutionOrderId, id));
        if (calculationDevided != null) {
            paidInfoDetailVO.setFinanceDevidedAmount(calculationDevided.getFinanceDevidedAmount());
            if(Objects.nonNull(contractExcutionOrder.getHandlingFeeRate()) && Objects.nonNull(calculationDevided.getFinanceDevidedAmount())) {
                paidInfoDetailVO.setHandlingFeeAmount(calculationDevided.getFinanceDevidedAmount()
                                .multiply(contractExcutionOrder.getHandlingFeeRate().divide(McnConstant.ONE_HUNDRED))
                                .divide(BigDecimal.ONE.add(contractExcutionOrder.getHandlingFeeRate().divide(McnConstant.ONE_HUNDRED)), 2, BigDecimal.ROUND_HALF_UP));
            }
        }
        // 如客户没有红人结算固定返点比例，返回年度返点比例
        if (customerVO.getFixedRebateRatio() == null) {
            if (calculationDevided != null) {
                excutionOrderDetailVO.setYearRebateRate(calculationDevided.getYearRebateRate());
            } else {
                excutionOrderDetailVO.setYearRebateRate(this.getYearRebateRate(contractExcutionOrder));
            }
        }
        excutionOrderDetailVO.setCalculationDevided(calculationDevided);
        excutionOrderDetailVO.setPaidInfo(paidInfoDetailVO);
        excutionOrderDetailVO.setStarAccountInfo(starAccountInfo);
        return starAccountInfo;
    }


    /**
     * 查询收入合同审批状态
     */
    public void incomeContractData(IncomeContract incomeContract, ExcutionOrderContractVO excutionOrderContractVO, Long contractProcessId) {
        Long allFlowIds = approvalFlowService.getFlowId(incomeContract.getId(), contractProcessId);
        excutionOrderContractVO.setFlowId(allFlowIds);
        List<Long> flowIds = new ArrayList<>(Collections.singletonList(allFlowIds));
        JSONObject flowIdsMapping = approvalFlowService.getFlowStatus(flowIds);
        if (Objects.nonNull(flowIdsMapping)) {
            if (flowIdsMapping.size() > 0 && Objects.nonNull(excutionOrderContractVO.getFlowId())) {
                excutionOrderContractVO.setFlowStatusName(flowIdsMapping.getString(excutionOrderContractVO.getFlowId().toString()));
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer update(ExcutionOrderUpdateDTO excutionOrderUpdateDTO, boolean verifyExcutorAuth) {
        ContractExcutionOrder beforeContractExcutionOrder = contractExcutionOrderMapper.selectById(excutionOrderUpdateDTO.getId());
        BusinessAssert.notNull(beforeContractExcutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        if(verifyExcutorAuth) {
            commonHelper.verifyExcutorAuth(beforeContractExcutionOrder.getExcutorId(), false);
        }
        //KOC红人校验
        if (ExcutionOrderTypeEnum.KOC_EXCUTION_ORDER.getType().equals(beforeContractExcutionOrder.getType())) {
            BusinessAssert.isTrue(StringUtils.isNotEmpty(excutionOrderUpdateDTO.getExcuteFeedback().getPublishUrl()), McnErrorCode.KOC_PUBLISH_URL);
            BusinessAssert.isTrue(excutionOrderUpdateDTO.getCalculationDevided().getSettlementMethod().equals(SettlementMethodEnum.BATCH_REMITTANCE.getCode()), McnErrorCode.KOC_IS_BATCH_REMITTANCE);
        }
        ExcuteFeedback excuteFeedback = excutionOrderUpdateDTO.getExcuteFeedback();
        CalculationDevided calculationDevided = excutionOrderUpdateDTO.getCalculationDevided();
        //若执行单当前状态为“待执行”或“执行中”时，执行单保存或提交时需校验修改后此字段值必须和修改前保持一致，否则提示：合同已提交，执行单“总收入（元）”无法修改，请确保修改后总收入金额仍为X元！
        BusinessAssert.isTrue(beforeContractExcutionOrder.getActualQuotedPrice().compareTo(excutionOrderUpdateDTO.getActualQuotedPrice()) == 0
                , McnErrorCode.CONTRACT_EXCUTION_ORDER_FEE_UPDATE_ERROR, String.format(McnErrorCode.CONTRACT_EXCUTION_ORDER_FEE_UPDATE_ERROR.message(), beforeContractExcutionOrder.getActualQuotedPrice()));
        ContractExcutionOrder afterContractExcutionOrder = new ContractExcutionOrder();
        verifyAndBatchConfirmDevided(excutionOrderUpdateDTO, beforeContractExcutionOrder, afterContractExcutionOrder);
        afterContractExcutionOrder.setAttachmentFile(excutionOrderUpdateDTO.getAttachmentFile());
        Integer save = contractExcutionOrderMapper.updateDetail(afterContractExcutionOrder);
        //保存执行反馈
        if (excuteFeedback != null) {
            this.saveExcuteFeedback(excuteFeedback, afterContractExcutionOrder);
        }
        //保存计算分成
        if (calculationDevided != null) {
            this.saveCalculationDevided(calculationDevided, afterContractExcutionOrder);
        }
        //日期更新同步更新【前置执行单】模块里的“发布日期”
        intentionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(DocIntentionOrder.class)
                .eq(DocIntentionOrder::getExcutionOrderId, afterContractExcutionOrder.getId())
                .set(DocIntentionOrder::getPublishDate, afterContractExcutionOrder.getPromisePublishDate())
                .set(DocIntentionOrder::getPublishDateEnd, afterContractExcutionOrder.getPromisePublishDateEnd())
                .set(DocIntentionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                .set(DocIntentionOrder::getUpdateName, UserVoContextHolder.getUserName())
                .set(DocIntentionOrder::getUpdateDate, new Date()));
        //更新红人分成比例
        //this.getOrUpdateDividedRate(excutionOrderUpdateDTO.getId(), null,true);
        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(beforeContractExcutionOrder.getId())
                .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                .compare(beforeContractExcutionOrder, afterContractExcutionOrder)
                .build());
        return save;
    }

    private void verifyAndBatchConfirmDevided(ExcutionOrderUpdateDTO excutionOrderUpdateDTO, ContractExcutionOrder beforeContractExcutionOrder, ContractExcutionOrder afterContractExcutionOrder) {
        BeanUtils.copyProperties(beforeContractExcutionOrder, afterContractExcutionOrder);
        afterContractExcutionOrder.setAccountId(excutionOrderUpdateDTO.getAccountId());
        afterContractExcutionOrder.setPaidWay(excutionOrderUpdateDTO.getPaidWay());
        afterContractExcutionOrder.setAccountType(excutionOrderUpdateDTO.getAccountType());
        afterContractExcutionOrder.setCustomerInvoiceWay(excutionOrderUpdateDTO.getCustomerInvoiceWay());
        afterContractExcutionOrder.setExcutorId(excutionOrderUpdateDTO.getExcutorId());
        afterContractExcutionOrder.setExcutorName(excutionOrderUpdateDTO.getExcutorName());
        afterContractExcutionOrder.setDividedRate(excutionOrderUpdateDTO.getDividedRate());
        afterContractExcutionOrder.setDividedRemark(excutionOrderUpdateDTO.getDividedRemark());
        afterContractExcutionOrder.setMicroTaskAmount(excutionOrderUpdateDTO.getMicroTaskAmount());
        afterContractExcutionOrder.setFansHeadlineAmount(excutionOrderUpdateDTO.getFansHeadlineAmount());
        afterContractExcutionOrder.setOtherFee(excutionOrderUpdateDTO.getOtherFee());
        afterContractExcutionOrder.setPlatformFee(excutionOrderUpdateDTO.getPlatformFee());
        afterContractExcutionOrder.setStarAccountInfoId(excutionOrderUpdateDTO.getStarAccountInfoId());
        afterContractExcutionOrder.setBrandName(excutionOrderUpdateDTO.getBrandName());
        afterContractExcutionOrder.setProductName(excutionOrderUpdateDTO.getProductName());
        //采购合同-新建自动关联执行单，不允许修改
        //afterContractExcutionOrder.setPurchaseCode(excutionOrderUpdateDTO.getPurchaseCode());
        afterContractExcutionOrder.setRealAmount(excutionOrderUpdateDTO.getRealAmount());
        afterContractExcutionOrder.setActualQuotedPrice(excutionOrderUpdateDTO.getActualQuotedPrice());
        afterContractExcutionOrder.setCoordinatorId(excutionOrderUpdateDTO.getCoordinatorId());
        afterContractExcutionOrder.setCoordinatorName(excutionOrderUpdateDTO.getCoordinatorName());
        if (Objects.nonNull(excutionOrderUpdateDTO.getApprovalStatus()) && excutionOrderUpdateDTO.getApprovalStatus() == ApprovalStatusEnum.APPROVAL.code()) {
            afterContractExcutionOrder.setDepartmentHeaderId(excutionOrderUpdateDTO.getDepartmentHeaderId());
            afterContractExcutionOrder.setDepartmentHeaderName(excutionOrderUpdateDTO.getDepartmentHeaderName());
            UserDTO userDTO = new UserDTO();
            userDTO.setUserId(excutionOrderUpdateDTO.getExcutorId());
            DepartmentHeadVO departmentHeadVO = privilegeClient.getDepartmentHead(userDTO).getObj();
            if (departmentHeadVO != null) {
                afterContractExcutionOrder.setExcutorDepartmentId(departmentHeadVO.getDepartmentId());
                afterContractExcutionOrder.setExcutorDepartmentName(departmentHeadVO.getDepartmentName());
            }
        }
        afterContractExcutionOrder.setYearCode(excutionOrderUpdateDTO.getYearCode());
        afterContractExcutionOrder.setInvoiceForm(excutionOrderUpdateDTO.getInvoiceForm());
        afterContractExcutionOrder.setInvoiceTitle(excutionOrderUpdateDTO.getInvoiceTitle());
        afterContractExcutionOrder.setInvoiceType(excutionOrderUpdateDTO.getInvoiceType());
        afterContractExcutionOrder.setInvoiceContent(excutionOrderUpdateDTO.getInvoiceContent());
        afterContractExcutionOrder.setStarBillingHeaderId(excutionOrderUpdateDTO.getStarBillingHeaderId());
        if (excutionOrderUpdateDTO.getApprovalStatus().equals(ExcutionApprovalStatusEnum.EXECUTING.getCode())) {
            if (beforeContractExcutionOrder.getStartExecutionDate() == null) {
                afterContractExcutionOrder.setStartExecutionDate(new Date());
            }
        }
        /**
         * 更新执行单操作人
         */
        if (ExcutionApprovalStatusEnum.anyMatch(excutionOrderUpdateDTO.getApprovalStatus(),
                ExcutionApprovalStatusEnum.EXECUTING, ExcutionApprovalStatusEnum.CONFIRMING, ExcutionApprovalStatusEnum.APPROVAL)) {
            afterContractExcutionOrder.setApprovalStatus(excutionOrderUpdateDTO.getApprovalStatus());
        }
        afterContractExcutionOrder.setStarPlatformInfoId(excutionOrderUpdateDTO.getStarPlatformInfoId());
        StarPlatformInfo starPlatformInfo = starPlatformInfoService.selectById(excutionOrderUpdateDTO.getStarPlatformInfoId());
        BusinessAssert.notNull(starPlatformInfo, "红人平台信息不存在");
        afterContractExcutionOrder.setStarId(starPlatformInfo.getStarId());
        afterContractExcutionOrder.setStarNickName(starPlatformInfo.getPlatNickName());
        //afterContractExcutionOrder.setInSystemAdmin(inSystemAdmin);
        afterContractExcutionOrder.setHaveLinkCommand(excutionOrderUpdateDTO.getHaveLinkCommand());
        //发布日期
        afterContractExcutionOrder.setPromisePublishDate(excutionOrderUpdateDTO.getPromisePublishDate());
        afterContractExcutionOrder.setPromisePublishDateEnd(excutionOrderUpdateDTO.getPromisePublishDateEnd());
        //执行单备注
        afterContractExcutionOrder.setRemark(excutionOrderUpdateDTO.getRemark());
        //发布形式
        afterContractExcutionOrder.setPublishForm(excutionOrderUpdateDTO.getPublishForm());
        //其他收入
        afterContractExcutionOrder.setOtherAmount(excutionOrderUpdateDTO.getOtherAmount());
        //其他收入说明
        afterContractExcutionOrder.setOtherAmountRemark(excutionOrderUpdateDTO.getOtherAmountRemark());
        //机酒差旅费用说明
        afterContractExcutionOrder.setSpecialFeeRemark(excutionOrderUpdateDTO.getSpecialFeeRemark());
        //其他补贴性收入
        afterContractExcutionOrder.setSubsidyIncomeAmount(excutionOrderUpdateDTO.getSubsidyIncomeAmount());
        //其他补贴性收入说明
        afterContractExcutionOrder.setSubsidyIncomeRemark(excutionOrderUpdateDTO.getSubsidyIncomeRemark());
        afterContractExcutionOrder.setCooperationContent(excutionOrderUpdateDTO.getCooperationContent());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveAndSubmit(ExcutionOrderUpdateDTO updateDTO, boolean isConfirm) {
        return DistributedLockTemplate.execute(OperateLockEnum.CONTRACT_EXCUTION_ORDER.generateKey(updateDTO.getId()), () -> {
                ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectById(updateDTO.getId());
                BusinessAssert.notNull(contractExcutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
                if(ExcutionApprovalStatusEnum.anyMatch(contractExcutionOrder.getApprovalStatus(), ExcutionApprovalStatusEnum.EXECUTED, ExcutionApprovalStatusEnum.CONFIRM_REJECTED)) {
                    updateDTO.setApprovalStatus(ExcutionApprovalStatusEnum.CONFIRMING.getCode());
                    addDepartmentHead(updateDTO.getExcutorId(), updateDTO);
                } else if(ExcutionApprovalStatusEnum.anyMatch(contractExcutionOrder.getApprovalStatus(),  ExcutionApprovalStatusEnum.CONFIRMING, ExcutionApprovalStatusEnum.CANCEL, ExcutionApprovalStatusEnum.REJECTED)) {
                    updateDTO.setApprovalStatus(isConfirm ? ExcutionApprovalStatusEnum.CONFIRMING.getCode() : ExcutionApprovalStatusEnum.APPROVAL.getCode());
                } else {
                    throw new BusinessException(McnErrorCode.DATA_OPERATION_NOT_SUPPORTED.getCode(), "单据状态已变更，不支持该操作！");
                }
                this.update(updateDTO, false);
                Integer approvalStatus = updateDTO.getApprovalStatus();
                ContractExcutionOrder newContractExcutionOrder = contractExcutionOrderMapper.selectById(contractExcutionOrder.getId());
                if (ExcutionApprovalStatusEnum.isConfirming(approvalStatus)) {
                    IncomeContract incomeContract = incomeContractService.selectById(contractExcutionOrder.getIncomeContractId());
                    verifyConfirmAndApproval(newContractExcutionOrder, incomeContract, false);
                } else if (ExcutionApprovalStatusEnum.isApproval(approvalStatus)) {
                    IncomeContract incomeContract = incomeContractMapper.selectById(contractExcutionOrder.getIncomeContractId());
                    BusinessAssert.isTrue(Objects.nonNull(incomeContract) && ApprovalStatusEnum.isPassed(incomeContract.getApprovalStatus()), McnErrorCode.INCOME_NOT_APPROVED);
                    verifyConfirmAndApproval(newContractExcutionOrder, incomeContract, true);
                }
                return true;
        });
    }

    /**
     * 提起审批
     *
     * @param incomeContract
     * @param contractExcutionOrder
     * @param calculationDevided
     * @param approvalEnum
     * @param param
     */
    private void startProcess(IncomeContract incomeContract, ContractExcutionOrder contractExcutionOrder, ExcuteFeedback excuteFeedback, CalculationDevided calculationDevided, ApprovalEnum approvalEnum, String param) {
        if(IncomeContractTypeEnum.isFormalContract(incomeContract.getContractType())
                && NumberCst.ZERO.equals(contractExcutionOrder.getInSystemAdmin())
                && SettlementMethodEnum.isReceivePayment(calculationDevided.getSettlementMethod())
                && ObjectUtils.defaultIfNull(calculationDevided.getAmountReceivable(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) == 1) {
            // 校验原收入合同对用费用表是否有未作废的费用
            Integer invalidCount = financeClient.getInvalid(incomeContract.getContractCode(), contractExcutionOrder.getExcuteCode(), null).getObj();
            BusinessAssert.isTrue(invalidCount <= 0, McnErrorCode.BUSINESS_ERROR, "该执行单已经生成内部红人应收费用，请先作废内部红人应收费用！");

        }
        ContractExcutionOrder updateEntity = new ContractExcutionOrder();
        updateEntity.setId(contractExcutionOrder.getId());
        //【正式执行单】提交审批时，系统自动将“实际发布日期”更新到【正式执行单】里的“发布日期”（开始时间=结束时间），同时触发更新【前置执行单】里的“发布日期”（开始时间=结束时间）
        updateEntity.setPromisePublishDate(excuteFeedback.getRealPublishDate());
        updateEntity.setPromisePublishDateEnd(excuteFeedback.getRealPublishDate());
        contractExcutionOrder.setPromisePublishDate(null);
        contractExcutionOrder.setPromisePublishDateEnd(null);
        intentionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(DocIntentionOrder.class)
                .eq(DocIntentionOrder::getExcutionOrderId, contractExcutionOrder.getId())
                .set(DocIntentionOrder::getPublishDate, excuteFeedback.getRealPublishDate())
                .set(DocIntentionOrder::getPublishDateEnd, excuteFeedback.getRealPublishDate())
                .set(DocIntentionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                .set(DocIntentionOrder::getUpdateName, UserVoContextHolder.getUserName())
                .set(DocIntentionOrder::getUpdateDate, new Date()));
        UserVO userVo = UserVoContextHolder.getUserVo();
        updateEntity.setApprovalBy(userVo.getUserId());
        updateEntity.setApprovalName(userVo.getRealName());
        updateEntity.setApprovalDate(new Date());
        contractExcutionOrderMapper.updateById(updateEntity);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("settlementMethod", calculationDevided.getSettlementMethod());
        approvalFlowService.startProcess(contractExcutionOrder.getId(), contractExcutionOrder.getExcuteCode(), approvalEnum, param, jsonObject.toJSONString());
    }

    /**
     * 校验总金额--现在已经剔除 不再需要这个金额校验了 因为校验值就行了
     * @param contractExcutionOrder
     */
    private void verifyTotalAmount(ContractExcutionOrder contractExcutionOrder, CalculationDevided calculationDevided) {
        if(ExcutionOrderTypeEnum.isInside(contractExcutionOrder.getType())) {
            //内部红人执行单 执行单总金额=实际报价+微任务金额+粉丝头条金额+平台手续费+其他收费
            //剔除 微任务金额 粉丝头条金额
            BusinessAssert.isTrue(contractExcutionOrder.getActualQuotedPrice().compareTo(
                    contractExcutionOrder.getRealAmount()
//                            .add(contractExcutionOrder.getMicroTaskAmount())
//                            .add(contractExcutionOrder.getFansHeadlineAmount())
                            .add(contractExcutionOrder.getPlatformFee())
                            .add(contractExcutionOrder.getOtherFee())) == 0,
                    McnErrorCode.EXCUTION_TOTAL_AMOUNT_WRONG,  "执行单总金额须等于实际报价+平台手续费+其他收费"
            );
        } else if (ExcutionOrderTypeEnum.OUTSIDE_EXCUTION_ORDER.getType().equals(contractExcutionOrder.getType())) {
            // 外部红人执行单(不包括KOC红人） 执行单本单到手价不为0时校验：执行单总金额 = 本单到手价 + 其他费用
            BusinessAssert.isTrue(contractExcutionOrder.getActualQuotedPrice().compareTo(
                    ObjectUtils.defaultIfNull(calculationDevided.getHandPrice(), BigDecimal.ZERO)
                            .add(ObjectUtils.defaultIfNull(contractExcutionOrder.getOtherFee(), BigDecimal.ZERO))) == 0,
                    McnErrorCode.EXCUTION_TOTAL_AMOUNT_WRONG,  "执行单总金额须等于本单固定到手价+其他收费"
            );
        }
    }


    private  void verifyPurchase(ContractExcutionOrder contractExcutionOrder) {
        if (StringUtils.isNotBlank(contractExcutionOrder.getPurchaseCode())) {
            PurchaseContract purchaseContract = purchaseContractMapper.selectOne(Wrappers.lambdaQuery(PurchaseContract.class).eq(PurchaseContract::getContractCode, contractExcutionOrder.getPurchaseCode()));
            Assert.isTrue(purchaseContract.getPurchaseStatus().equals(ApprovalStatusEnum.PASSED.code()), "执行单关联的采购合同需审批通过！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAndComplete(ExcutionOrderUpdateDTO excutionOrderUpdateDTO) {
        excutionOrderUpdateDTO.setApprovalStatus(ExcutionApprovalStatusEnum.EXECUTED.getCode());
        addDepartmentHead(excutionOrderUpdateDTO.getExcutorId(), excutionOrderUpdateDTO);
        this.update(excutionOrderUpdateDTO, true);
        ExcutionOrderChangeStatusDTO statusDTO = new ExcutionOrderChangeStatusDTO();
        statusDTO.setExcutionOrderId(excutionOrderUpdateDTO.getId());
        statusDTO.setApprovalStatus(excutionOrderUpdateDTO.getApprovalStatus());
        this.changeStatus(statusDTO, false);
    }

    private void addDepartmentHead(Long userId, ExcutionOrderUpdateDTO excutionOrderUpdateDTO) {
        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(userId);
        DepartmentHeadVO departmentHeadVO = privilegeClient.getDepartmentHead(userDTO).getObj();
        if (departmentHeadVO != null && departmentHeadVO.getDepartmentHead() != null) {
            excutionOrderUpdateDTO.setDepartmentHeaderId(departmentHeadVO.getDepartmentHeadId());
            excutionOrderUpdateDTO.setDepartmentHeaderName(departmentHeadVO.getDepartmentHead().getUsername());
        }
    }

    @Override
    public Page<ExcutionOrderVO> getPage(McnPage<ExcutionOrderVO> mcnPage, ExcutionOrderSearchDTO excutionOrderSearchDTO) {
        mcnPage.setPageNum(excutionOrderSearchDTO.getPageNum());
        mcnPage.setPageSize(excutionOrderSearchDTO.getPageSize());
        excutionOrderSearchDTO.setAlias("ceo.");
        excutionOrderSearchDTO.setProcessIds(ApprovalEnum.getExecutionOrderProcessIds());
        if (CollectionUtils.isNotEmpty(excutionOrderSearchDTO.getFlowStatus())) {
            List<Long> allList = approvalFlowService.getSrcList(excutionOrderSearchDTO.getFlowStatus(), excutionOrderSearchDTO.getProcessIds());
            if (CollectionUtil.isEmpty(allList)) {
                return new Page<>();
            }
            excutionOrderSearchDTO.setSrcIds(allList);
        }
        //内容组过滤
        if(CollectionUtils.isNotEmpty(excutionOrderSearchDTO.getSubDepartmentIdList())) {
            List<Long> starAgentIds = privilegeClient.getUserIdsByDeptIds(excutionOrderSearchDTO.getSubDepartmentIdList()).getObj();
            List<Long> starIds = null;
            if(CollectionUtils.isNotEmpty(starAgentIds)) {
                starIds = CommonUtil.defaultList(starBasicDataMapper.selectList(Wrappers.lambdaQuery(StarBasicData.class)
                        .select(StarBasicData::getId).in(StarBasicData::getStarAgentId, starAgentIds).eq(StarBasicData::getIsDelete, NumberCst.ZERO)))
                        .stream().map(StarBasicData::getId).collect(Collectors.toList());
            }
            excutionOrderSearchDTO.setStarIds(CommonUtil.defaultList(starIds, -1L));
        }
        Page<ExcutionOrderVO> page = contractExcutionOrderMapper.getPage(mcnPage, excutionOrderSearchDTO);
        List<ExcutionOrderVO> records = page.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            //查询FlowId
            List<Long> idList = records.stream().map(ExcutionOrderVO::getId).collect(Collectors.toList());
            Map<Long, Long> flowMap = approvalFlowService.getNewestFlowIds(idList, ApprovalEnum.getExecutionOrderProcessIds());
            List<String> brandCodes = records.stream().map(ExcutionOrderVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            records.forEach(record -> {
                record.setFlowId(CommonUtil.getMapValue(flowMap, record.getId()));
                record.setApprovalStatusName(ExcutionApprovalStatusEnum.getStatusName(record.getApprovalStatus()));
                record.setPaybackStatusName(PaybackStatusEnum.getStatusName(record.getPaybackStatus()));
                record.setContractApprovalStatusName(ApprovalStatusEnum.getStatusName(record.getContractApprovalStatus()));
                record.setContractPaybackStatusName(PaybackStatusEnum.getStatusName(record.getContractPaybackStatus()));
                record.setRebateSettleStatusName(CommonSettleStatusEnum.getStatusName(record.getRebateSettleStatus()));
                if(brandMap.containsKey(record.getBrandName())) {
                    record.setBrandName(brandMap.get(record.getBrandName()));
                }
            });
            //查询客户名称
            List<Long> customerIdList = records.stream().map(ExcutionOrderVO::getCustomerId).collect(Collectors.toList());
            Map<Long, BaseCustomer> customerMap = baseInfoClient.getMcnCustomerByIds(customerIdList).getObj();
            if (MapUtils.isNotEmpty(customerMap)) {
                records.forEach(record -> {
                    if (customerMap.get(record.getCustomerId()) != null) {
                        record.setCustomerName(customerMap.get(record.getCustomerId()).getCustomerNameC());
                    }
                });
            }
            //审批名称
            List<Long> flowList = records.stream().map(ExcutionOrderVO::getFlowId).filter(Objects::nonNull).collect(Collectors.toList());
            JSONObject jsonObject = approvalFlowService.getFlowStatus(flowList);
            if (MapUtils.isNotEmpty(jsonObject)) {
                records.forEach(record -> {
                    record.setFlowStatusName(CommonUtil.defaultString(jsonObject, record.getFlowId()));
                });
            }
            //查询平台名称
            List<Long> starPlatInfoIds = records.stream().map(ExcutionOrderVO::getStarPlatformInfoId).collect(Collectors.toList());
            List<StarPlatInfoVO> starInfoList = starPlatformInfoService.getByIds(starPlatInfoIds);
            Map<Long, StarPlatInfoVO> starPlatInfoVoMap = starInfoList.stream().collect(Collectors.toMap(StarPlatInfoVO::getId, starPlatInfoVO -> starPlatInfoVO));
            if (MapUtils.isNotEmpty(starPlatInfoVoMap)) {
                records.forEach(record -> {
                    if (starPlatInfoVoMap.containsKey(record.getStarPlatformInfoId())) {
                        StarPlatInfoVO starPlatInfoVO = starPlatInfoVoMap.get(record.getStarPlatformInfoId());
                        record.setPlatformName(starPlatInfoVO.getPlatformName());
                        record.setStarAgentId(starPlatInfoVO.getStarAgentId());
                        record.setStarAgentName(starPlatInfoVO.getStarAgentName());
                    }
                });
            }
        }
        return page;
    }


    @Override
    public List<ExcutionExportVO> export(ExcutionOrderSearchDTO excutionOrderSearchDTO) {
        excutionOrderSearchDTO.setAlias("ceo.");
        excutionOrderSearchDTO.setProcessIds(ApprovalEnum.getExecutionOrderProcessIds());
        if (CollectionUtils.isNotEmpty(excutionOrderSearchDTO.getFlowStatus())) {
            List<Long> allList = approvalFlowService.getSrcList(excutionOrderSearchDTO.getFlowStatus(), excutionOrderSearchDTO.getProcessIds());
            if (CollectionUtils.isEmpty(allList)) {
                return null;
            }
            excutionOrderSearchDTO.setSrcIds(allList);
        }
        //内容组过滤
        if(CollectionUtils.isNotEmpty(excutionOrderSearchDTO.getSubDepartmentIdList())) {
            List<Long> starAgentIds = privilegeClient.getUserIdsByDeptIds(excutionOrderSearchDTO.getSubDepartmentIdList()).getObj();
            List<Long> starIds = null;
            if(CollectionUtils.isNotEmpty(starAgentIds)) {
                starIds = CommonUtil.defaultList(starBasicDataMapper.selectList(Wrappers.lambdaQuery(StarBasicData.class)
                        .select(StarBasicData::getId).in(StarBasicData::getStarAgentId, starAgentIds).eq(StarBasicData::getIsDelete, NumberCst.ZERO)))
                        .stream().map(StarBasicData::getId).collect(Collectors.toList());
            }
            excutionOrderSearchDTO.setStarIds(CommonUtil.defaultList(starIds, -1L));
        }
        List<ExcutionExportVO> page = contractExcutionOrderMapper.exportList(excutionOrderSearchDTO);
        if (CollectionUtils.isNotEmpty(page)) {
            List<Long> idList = page.stream().map(ExcutionExportVO::getId).distinct().collect(Collectors.toList());
            /** 查询平台名称 */
            List<Long> starPlatInfoIds = page.stream().map(ExcutionExportVO::getStarPlatformInfoId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<StarPlatInfoVO> starInfoList = starPlatformInfoService.getByIds(starPlatInfoIds);
            Map<Long, StarPlatInfoVO> starPlatInfoMap = starInfoList.stream().collect(Collectors.toMap(StarPlatInfoVO::getId, starPlatInfoVO -> starPlatInfoVO));

            /** 查询红人结算固定返点比例 */
            List<Long> customerIds = page.stream().map(ExcutionExportVO::getCustomerId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<Long, BaseCustomer> customerMap = baseInfoClient.getMcnCustomerByIds(customerIds).getObj();

            //我司合同主体
            Map<Long, String> companyMap = CommonUtil.defaultList(privilegeClient.getParList().getObj()).
                    stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));

            //获取红人平台结算信息
//            List<Long> starPlatformInfoIds = page.stream().map(ExcutionExportVO::getStarPlatformInfoId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
//            Map<Long, StarPlatformSettlementInfo> starPlatformSettlementInfoMap = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(starPlatformInfoIds), () ->
//                    CommonUtil.defaultList(starPlatformSettlementInfoMapper.selectList(Wrappers.lambdaQuery(StarPlatformSettlementInfo.class)
//                            .in(StarPlatformSettlementInfo::getStarPlatformInfoId, starPlatformInfoIds)
//                            .eq(StarPlatformSettlementInfo::getIsDelete, NumberCst.ZERO))).stream().collect(Collectors.toMap(StarPlatformSettlementInfo::getId, Function.identity())),
//                    Collections.EMPTY_MAP);
            //计算分成信息获取
            Map<Long, CalculationDevided> calculationDevidedMap = CommonUtil.defaultList(calculationDevidedMapper.selectList(Wrappers.lambdaQuery(CalculationDevided.class)
                    .in(CalculationDevided::getExcutionOrderId, idList).in(CalculationDevided::getIsDelete, NumberCst.ZERO))).stream().collect(Collectors.toMap(CalculationDevided::getExcutionOrderId, calculationDevided -> calculationDevided));

            //查询意向单信息
            Map<Long, DocIntentionOrder> intentionOrderMap  = CommonUtil.defaultList(intentionOrderMapper.selectList(Wrappers.lambdaQuery(DocIntentionOrder.class)
                    .in(DocIntentionOrder::getExcutionOrderId, idList).eq(DocIntentionOrder::getIsDelete, NumberCst.ZERO)))
            .stream().collect(Collectors.toMap(DocIntentionOrder::getExcutionOrderId, Function.identity()));
            //红人收款账号信息列表
            List<Long> starAccountInfoIds = page.stream().map(ExcutionExportVO::getStarAccountInfoId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<Long, StarAccountInfo> starAccountInfoMap= CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(starAccountInfoIds), () ->
                    starAccountInfoMapper.selectBatchIds(starAccountInfoIds).stream().collect(Collectors.toMap(StarAccountInfo::getId, starAccountInfo -> starAccountInfo)), Collections.EMPTY_MAP);
            //财务回款流水信息
            List<String> executeCodeList = page.stream().map(ExcutionExportVO::getExcuteCode).distinct().collect(Collectors.toList());
            Map<String, ClearData4ExecuteOrderVo> clearData4ExecuteOrderVoMap = financeClient.clearData4ExecuteOrder(executeCodeList).getObj();
            //合作内容
            Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.ACTIVE_PLATFORMS);
            //查询品牌
            List<String> brandCodes = page.stream().map(ExcutionExportVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            for (ExcutionExportVO record : page) {
                record.setApprovalStatusName(ExcutionApprovalStatusEnum.getStatusName(record.getApprovalStatus()));
                if (starPlatInfoMap.containsKey(record.getStarPlatformInfoId())) {
                    StarPlatInfoVO starPlatInfoVO = starPlatInfoMap.get(record.getStarPlatformInfoId());
                    record.setPlatformName(starPlatInfoVO.getPlatformName());
                    record.setStarName(starPlatInfoVO.getStarRealName());
                    record.setPlatNickName(starPlatInfoVO.getPlatNickName());
                    record.setIsAllPlatform(starPlatInfoVO.getIsAllPlatform());
                    record.setPlatformId(starPlatInfoVO.getPlatformId());
                }
                if (customerMap.containsKey(record.getCustomerId())) {
                    BaseCustomer baseCustomer = customerMap.get(record.getCustomerId());
                    record.setCustomerName(baseCustomer.getCustomerNameC());
                }
                if(companyMap.containsKey(record.getContractingId())) {
                    record.setCompanyContractSubject(companyMap.get(record.getContractingId()));
                }
                //获取红人分成比例信息
                record.setStarDevidedRate(record.getDividedRate());
                record.setCooperationContent(record.getCooperationContent());
                //赋值意向单编号
                DocIntentionOrder docIntentionOrder = intentionOrderMap.get(record.getId());
                if(Objects.nonNull(docIntentionOrder)) {
                    record.setIntentionCode(docIntentionOrder.getIntentionCode());
                    record.setIsLiveAd(docIntentionOrder.getIsLiveAd());
                    record.setHaveDiscountApproval(docIntentionOrder.getHaveDiscountApproval());
                }
                //赋值计算分成相关信息
                if(calculationDevidedMap.containsKey(record.getId())){
                    CalculationDevided devided = calculationDevidedMap.get(record.getId());
                    //结算方式
                    record.setSettlementMethod(devided.getSettlementMethod());
                    //结算形式
                    record.setSettlementForm(devided.getSettlementForm());
                    //本单固定到手价
                    record.setHandPrice(devided.getHandPrice());
                    //应收金额
                    record.setAmountReceivable(devided.getAmountReceivable());
                    //内容报价返点比例（%）即 AE确认客户返点比例
                    record.setAeCustomerRabateRate(devided.getAeCustomerRabateRate());
                    //内容报价返点金额
                    record.setAeCustomerRabateAmount(devided.getAeCustomerRabateAmount());
                    //本单实际优惠比例（%）新增
                    record.setActualDiscountRatio(devided.getActualDiscountRatio());
                    //系统计算分成金额
                    record.setSysDevidedAmount(devided.getSysDevidedAmount());
                    //AE确认分成金额
                    record.setAeDevidedAmount(devided.getAeDevidedAmount());
                    //财务确认分成金额
                    record.setFinanceDevidedAmount(devided.getFinanceDevidedAmount());
                    //系统计算文建税
                    record.setSysCulturalTax(devided.getSysCulturalTax());
                    //AE确认文建税
                    record.setAeCulturalTax(devided.getAeCulturalTax());
                    //财务确认文建税
                    record.setFinanceCulturalTax(devided.getFinanceCulturalTax());
                    //AE分成金额备注
                    record.setAeDevidedRemark(devided.getRemark());
                    //财务分成金额备注
                    record.setFinanceDevidedRemark(devided.getFinanceDevidedRemark());
                }
                //赋值SAI 即star_account_info 红人收款账号信息相关
                if(starAccountInfoMap.containsKey(record.getStarAccountInfoId())){
                    StarAccountInfo accountInfo=starAccountInfoMap.get(record.getStarAccountInfoId());
                    record.setAccountName(accountInfo.getAccountName());
                    record.setStudioPayment(accountInfo.getStudioPayment());
                    record.setTaxRate(accountInfo.getTaxRate());
                    record.setAccountNumber(accountInfo.getAccountNumber());
                    record.setAccountBank(accountInfo.getAccountBank());
                    record.setAccountBranchBank(accountInfo.getAccountBranchBank());
                    record.setAccountProvince(accountInfo.getAccountProvince());
                    record.setAccountCity(accountInfo.getAccountCity());
                    record.setAccountIdCard(accountInfo.getAccountIdCard());
                    record.setAccountPhone(accountInfo.getAccountPhone());
                }
                if(MapUtils.isNotEmpty(clearData4ExecuteOrderVoMap) && clearData4ExecuteOrderVoMap.containsKey(record.getExcuteCode())) {
                    ClearData4ExecuteOrderVo clearData4ExecuteOrderVo = clearData4ExecuteOrderVoMap.get(record.getExcuteCode());
                    record.setClearNo(clearData4ExecuteOrderVo.getClearNo());
                    record.setClearDate(clearData4ExecuteOrderVo.getClearDate());
                    record.setRecordSeqNo(clearData4ExecuteOrderVo.getRecordSeqNo());
                    record.setArapDate(clearData4ExecuteOrderVo.getArapDate());
                    record.setCollectionUnit(clearData4ExecuteOrderVo.getCollectionUnit());
                    record.setPaybackCompany(clearData4ExecuteOrderVo.getPayCompany());
                    record.setPaybackArrivalAmount(clearData4ExecuteOrderVo.getAmount());
                }
                //翻译合作内容
                if(Objects.nonNull(record.getPlatformId()) && Objects.nonNull(record.getCooperationContent())) {
                    Map<String, String> cooperationContentMap = secondlevelDictMap.get(record.getPlatformId());
                    if(CommonUtil.containsKey(cooperationContentMap, record.getCooperationContent())) {
                        record.setCooperationContent(cooperationContentMap.get(record.getCooperationContent()));
                    }
                }
                if(brandMap.containsKey(record.getBrandName())) {
                    record.setBrandName(brandMap.get(record.getBrandName()));
                }
            }
            //字典翻译
            DictTranslationUtils.translation(() -> DictStream.of(
                    DictStream.map(DictTypeCst.FORMAL_CONTRACT, ExcutionExportVO::getOrderPlatform, ExcutionExportVO::setOrderPlatform),
                    DictStream.map(DictTypeCst.SETTLEMENT_METHOD, ExcutionExportVO::getSettlementMethod, ExcutionExportVO::setSettlementMethod)
                    ),(dictProfileList, dictList) -> Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                            .setDictsCodes(dictList.stream().distinct().collect(Collectors.toList())).setProfileCodes(dictProfileList))).getObj(),
                    page
            );
            //初始化发布形式信息
            docIntentionOrderService.initRecordPublishFormName(starPlatInfoMap,page);
        }
        return page;
    }

    /**
     * 修改执行单状态
     *
     * @param statusDTO
     * @param fromController
     * @return {@link Integer}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeStatus(ExcutionOrderChangeStatusDTO statusDTO, boolean fromController) {
        Long executionOrderId = statusDTO.getExcutionOrderId();
        Integer approvalStatus = statusDTO.getApprovalStatus();
        ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectById(executionOrderId);
        BusinessAssert.notNull(contractExcutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        validateStatus(contractExcutionOrder, approvalStatus);
        Date now = new Date();
        LambdaUpdateWrapper<ContractExcutionOrder> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
        //作废执行单
        if (ExcutionApprovalStatusEnum.isInvalid(approvalStatus)) {
            if (ExcutionApprovalStatusEnum.PAID.getCode().equals(contractExcutionOrder.getApprovalStatus())) {
                throw new BusinessException(McnErrorCode.EXECUTION_ORDER_HAS_BEEN_PRINTED);
            }
            Integer relatedCount;
            if (ExcutionApprovalStatusEnum.isPassed(contractExcutionOrder.getApprovalStatus())) {
                //判断该执行单关联的费用是否作废
                relatedCount = financeClient.getInvalid(contractExcutionOrder.getExcuteCode(), contractExcutionOrder.getIncomeContractCode(), null).getObj();
                BusinessAssert.isFalse(relatedCount > 0, McnErrorCode.INVALID_FAILED,"请先作废该执行单生成的相应费用（来源单号）");
            }
            relatedCount = financeClient.getInvalid(contractExcutionOrder.getIncomeContractCode(), contractExcutionOrder.getExcuteCode(), null).getObj();
            BusinessAssert.isFalse(relatedCount > 0, McnErrorCode.INVALID_FAILED, "请先作废该执行单关联的收入费用（来源明细）");


            //解除意向单关联
            intentionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(DocIntentionOrder.class)
                    .eq(DocIntentionOrder::getExcutionOrderId, executionOrderId)
                    .set(DocIntentionOrder::getExcutionOrderId, null)
                    .set(DocIntentionOrder::getExcutionOrderCode, null)
                    .set(DocIntentionOrder::getIncomeContractId, null)
                    .set(DocIntentionOrder::getIncomeContractCode, null)
                    .set(DocIntentionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(DocIntentionOrder::getUpdateName, UserVoContextHolder.getUserName())
                    .set(DocIntentionOrder::getUpdateDate, now));
//        } else if (ExcutionApprovalStatusEnum.CONFIRMED.code().equals(approvalStatus)) {
//            StarPlatInfoVO starPlatInfoVO = starPlatformInfoService.getById(contractExcutionOrder.getStarPlatformInfoId());
//            BusinessAssert.isTrue(Objects.nonNull(starPlatInfoVO) && UserVoContextHolder.isCurrentUser(starPlatInfoVO.getStarAgentId()), "非本单红人经纪人，不允许操作！");
        } else if(ExcutionApprovalStatusEnum.CONFIRM_REJECTED.code().equals(approvalStatus)) {
            StarPlatInfoVO starPlatInfoVO = starPlatformInfoService.getById(contractExcutionOrder.getStarPlatformInfoId());
            BusinessAssert.isTrue(Objects.nonNull(starPlatInfoVO) && UserVoContextHolder.isCurrentUser(starPlatInfoVO.getStarAgentId()), "非本单红人经纪人，不允许操作！");
        } else if (ExcutionApprovalStatusEnum.isApproval(approvalStatus)) {
            IncomeContract incomeContract = incomeContractMapper.selectById(contractExcutionOrder.getIncomeContractId());
            BusinessAssert.isTrue(Objects.nonNull(incomeContract) && ApprovalStatusEnum.isPassed(incomeContract.getApprovalStatus()), McnErrorCode.INCOME_NOT_APPROVED);
            verifyConfirmAndApproval(contractExcutionOrder, incomeContract, true);
        } else if (ExcutionApprovalStatusEnum.EXECUTING.code().equals(approvalStatus)) {
            commonHelper.verifyExcutorAuth(contractExcutionOrder.getExcutorId(), false);
            if(StringUtils.isNotBlank(statusDTO.getAePublishRemark())) {
                lambdaUpdateWrapper.set(ContractExcutionOrder::getAePublishRemark, statusDTO.getAePublishRemark())
                        .set(ContractExcutionOrder::getAePublishAttachment, statusDTO.getAePublishAttachment());
            } else {
                //关联合同或者关联补充协议单据状态非「审批通过」，弹窗提示用户添加备注信息，备注信息为必填项
                IncomeContract incomeContract = incomeContractMapper.selectById(contractExcutionOrder.getIncomeContractId());
                if(Objects.nonNull(incomeContract)) {
                    BusinessAssert.isTrue(ApprovalStatusEnum.isPassed(incomeContract.getApprovalStatus()), McnErrorCode.EXCUTION_ORDER_CONTRACT_NO_PASSED);
                }
                if(Objects.nonNull(contractExcutionOrder.getContractAgreementId())) {
                    IncomeContractAgreement incomeContractAgreement = incomeContactAgreementMapper.selectById(contractExcutionOrder.getContractAgreementId());
                    if(Objects.nonNull(incomeContractAgreement)) {
                        BusinessAssert.isTrue(ApprovalStatusEnum.isPassed(incomeContractAgreement.getApprovalStatus()), McnErrorCode.EXCUTION_ORDER_CONTRACT_NO_PASSED);
                    }
                }
            }
        }
        if (ExcutionApprovalStatusEnum.anyMatch(approvalStatus, ExcutionApprovalStatusEnum.CANCEL, ExcutionApprovalStatusEnum.INVALID)
            && ExcutionApprovalStatusEnum.isApproval(contractExcutionOrder.getApprovalStatus())) {
            Long processId = null;
            if (ExcutionOrderTypeEnum.INSIDE_EXCUTION_ORDER.getType().equals(contractExcutionOrder.getType())) {
                processId = ApprovalEnum.EXECUTION_INSIDE_STAR.getProcessId();
            }
            if (ExcutionOrderTypeEnum.isOutside(contractExcutionOrder.getType())) {
                processId = ApprovalEnum.EXCUTION_OUTSIDE_STAR.getProcessId();
            }
            approvalFlowService.revokeProcess(contractExcutionOrder.getId(), processId);
            CalculationDevided calculationDevided = calculationDevidedMapper.selectOne(Wrappers.lambdaQuery(CalculationDevided.class)
                    .eq(CalculationDevided::getExcutionOrderId, executionOrderId)
                    .eq(CalculationDevided::getIsDelete, NumberCst.ZERO));
            BusinessAssert.notNull(calculationDevided, McnErrorCode.NO_CALCULATION_DEVIDED);
            if (ExcutionApprovalStatusEnum.CANCEL.code().equals(approvalStatus)) {
                calculationDevidedMapper.updateByNoStrategy(Wrappers.<CalculationDevided>lambdaUpdate()
                        .set(CalculationDevided::getFinanceDevidedAmount, null)
                        .set(CalculationDevided::getAmountReceivable, null)
                        .set(CalculationDevided::getFinanceCulturalTax, null)
                        .set(CalculationDevided::getFinanceDevidedRemark, null)
                        .set(CalculationDevided::getUpdateBy, UserVoContextHolder.getUserId())
                        .set(CalculationDevided::getUpdateName, UserVoContextHolder.getUserName())
                        .set(CalculationDevided::getUpdateDate, now)
                        .eq(CalculationDevided::getId, calculationDevided.getId()));
            }
            lambdaUpdateWrapper.set(ContractExcutionOrder::getPaidWay, null)
                    .set(ContractExcutionOrder::getAccountId, null)
                    .set(ContractExcutionOrder::getAccountType, null)
                    .set(ContractExcutionOrder::getHandlingFeeRate, null)
                    .set(ContractExcutionOrder::getCustomerInvoiceWay, null);
        }
        //更新执行单
        contractExcutionOrderMapper.updateByNoStrategy(lambdaUpdateWrapper
                .set(ContractExcutionOrder::getApprovalStatus, approvalStatus)
                .set(ContractExcutionOrder::getApprovalStatus, approvalStatus)
                .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                .set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                .set(ContractExcutionOrder::getUpdateDate, now)
                .eq(ContractExcutionOrder::getId, contractExcutionOrder.getId()));
        ContractExcutionOrder afterContractExcutionOrder = contractExcutionOrderMapper.selectById(contractExcutionOrder.getId());
        afterContractExcutionOrder.setReason(statusDTO.getReason());
        //发送日志
        EventPublisher.post(OperateLogEvent.builder().businessId(contractExcutionOrder.getId())
                .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                .actionName(fromController, ExcutionApprovalStatusEnum.getActionName(approvalStatus))
                .compare(contractExcutionOrder, afterContractExcutionOrder)
                .build());
        return Boolean.TRUE;
    }

    /**
     * 校验确认
     * @param contractExcutionOrder
     * @param incomeContract
     * @param isApproval
     */
    private void verifyConfirmAndApproval(ContractExcutionOrder contractExcutionOrder, IncomeContract incomeContract, boolean isApproval) {
        BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
        Long executionOrderId = contractExcutionOrder.getId();
        //提交确认-必须校验补充协议必须审批通过
        if (!isApproval && Objects.nonNull(contractExcutionOrder.getContractAgreementId())) {
            BusinessAssert.isTrue(incomeContactAgreementMapper.exist(Wrappers.lambdaQuery(IncomeContractAgreement.class)
                    .eq(IncomeContractAgreement::getId, contractExcutionOrder.getContractAgreementId())
                    .eq(IncomeContractAgreement::getIsDelete, Boolean.FALSE)
                    .eq(IncomeContractAgreement::getApprovalStatus, ApprovalStatusEnum.PASSED.code())), McnErrorCode.RELATED_AGREEMENT_NOT_PASSED);
        }
        List<ContractExcutionOrder> contractExcutionOrders = incomeContractService.confirmedAmount(incomeContract.getId());
        if (CollectionUtil.isEmpty(contractExcutionOrders)) {
            throw new BusinessException(McnErrorCode.NO_EXECUTION);
        }
        if (!IncomeContractTypeEnum.FRAME_CONTRACT.getType().equals(incomeContract.getContractType())) {
            List<ContractExcutionOrder> remainList = contractExcutionOrders.stream().filter(o -> !o.getId().equals(executionOrderId)).collect(Collectors.toList());
            remainList.add(contractExcutionOrder);
            if (IncomeContractTypeEnum.isLiveContract(incomeContract.getContractType())) {
                BigDecimal advAmtTotal = ObjectUtils.defaultIfNull(incomeContract.getRoiAdvAmt(), BigDecimal.ZERO).add(ObjectUtils.defaultIfNull(incomeContract.getNoroiAdvAmt(), BigDecimal.ZERO));
                this.verifyLiveContractExecutionAmount(remainList, advAmtTotal);
            } else if(isApproval){
                this.verifyExcutionAmount(remainList, incomeContract.getBusinessAmount());
            }
        }
        UserDTO userDTO = new UserDTO();
        userDTO.setUserId(contractExcutionOrder.getExcutorId());
        DepartmentHeadVO departmentHeadVO = privilegeClient.getDepartmentHead(userDTO).getObj();
        if (departmentHeadVO != null) {
            contractExcutionOrder.setExcutorDepartmentId(departmentHeadVO.getDepartmentId());
            contractExcutionOrder.setExcutorDepartmentName(departmentHeadVO.getDepartmentName());
            if (departmentHeadVO.getDepartmentHead() != null) {
                contractExcutionOrder.setDepartmentHeaderId(departmentHeadVO.getDepartmentHeadId());
                contractExcutionOrder.setDepartmentHeaderName(departmentHeadVO.getDepartmentHead().getUsername());
            }
        }
        CalculationDevided cd = calculationDevidedMapper.selectOne(Wrappers.lambdaQuery(CalculationDevided.class)
                .eq(CalculationDevided::getExcutionOrderId, contractExcutionOrder.getId()).eq(CalculationDevided::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(cd, McnErrorCode.NO_CALCULATION_DEVIDED);
        if(SettlementMethodEnum.isRemittance(cd.getSettlementMethod())) {
            if(ObjectUtils.defaultIfNull(cd.getAeDevidedAmount(), BigDecimal.ZERO).compareTo(ObjectUtils.defaultIfNull(cd.getSysDevidedAmount(), BigDecimal.ZERO))  != 0) {
                BusinessAssert.notBlank(cd.getRemark(), McnErrorCode.BUSINESS_ERROR, "AE确认分成金额≠系统计算分成金额，请在“分成金额备注”中进行差异说明！");
            }
        }
        //this.verifyTotalAmount(contractExcutionOrder, calculationDevided);
        ExcuteFeedback excuteFeedback = excuteFeedbackMapper.getByExcuteId(contractExcutionOrder.getId());
        BusinessAssert.notNull(excuteFeedback, "查询不到该执行单的执行反馈！");
        if(Objects.isNull(contractExcutionOrder.getDividedRate())) {
            this.getOrUpdateDividedRate(contractExcutionOrder.getId(), excuteFeedback.getRealPublishDate(), true);
        }
        if(isApproval) {
            //形式合同或者是平台下单的框架合同，结算方式判断
            if(IncomeContractTypeEnum.isFormalContract(incomeContract.getContractType())) {
                if(NumberCst.ZERO.equals(contractExcutionOrder.getInSystemAdmin())) {
                    BusinessAssert.isTrue(SettlementMethodEnum.isReceivePayment(cd.getSettlementMethod()),
                            "形式合同的执行单，红人未入驻情况下「结算方式」只能选择对私收款或对公收款");
                } else if(NumberCst.ONE.equals(contractExcutionOrder.getInSystemAdmin())){
                    BusinessAssert.isTrue(SettlementMethodEnum.isRemittance(cd.getSettlementMethod()),
                            "形式合同下的执行单，红人已入驻情况下「结算方式」只能选择单笔打款或批量打款");
                }
            } else if(IncomeContractTypeEnum.isLiveContract(incomeContract.getContractType()) && ObjectUtils.defaultIfNull(contractExcutionOrder.getPlatformReport(), Boolean.FALSE).booleanValue()) {
                if(NumberCst.ZERO.equals(contractExcutionOrder.getInSystemAdmin())) {
                    BusinessAssert.isTrue(SettlementMethodEnum.isReceivePayment(cd.getSettlementMethod()),
                            "框架合同平台下单的执行单，红人未入驻情况下「结算方式」只能选择对私收款或对公收款");
                } else if(NumberCst.ONE.equals(contractExcutionOrder.getInSystemAdmin())){
                    BusinessAssert.isTrue(SettlementMethodEnum.isRemittance(cd.getSettlementMethod()),
                            "框架合同平台下单的执行单，红人已入驻情况下「结算方式」只能选择单笔打款或批量打款");
                }
            }
//            StarPlatInfoVO starPlatInfoVO = starPlatformInfoService.getById(contractExcutionOrder.getStarPlatformInfoId());
//            if(Objects.nonNull(starPlatInfoVO) && NumberCst.ONE.equals(starPlatInfoVO.getIsAllPlatform())
//                    && NumberCst.ONE.equals(contractExcutionOrder.getInSystemAdmin())
//                    && !PaybackStatusEnum.isAllPayback(contractExcutionOrder.getPaybackStatus())) {
//                throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), "当前红人的执行单未回款，无法提交打款");
//            }
            this.remindDuplicateEntry(contractExcutionOrder, excuteFeedback);
            if (ExcutionOrderTypeEnum.isInside(contractExcutionOrder.getType())) {
                this.startProcess(incomeContract, contractExcutionOrder, excuteFeedback, cd, ApprovalEnum.EXECUTION_INSIDE_STAR, JSON.toJSONString(contractExcutionOrder));
            }
            if (ExcutionOrderTypeEnum.isOutside(contractExcutionOrder.getType())) {
                verifyPurchase(contractExcutionOrder);
                this.startProcess(incomeContract, contractExcutionOrder, excuteFeedback, cd, ApprovalEnum.EXCUTION_OUTSIDE_STAR, JSON.toJSONString(contractExcutionOrder));
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setPaid(ExcutionOrderPaidCallback paidCallback) {
        String messageBody = JSONObject.toJSONString(paidCallback);
        MessageInfo messageInfo = MessageInfo.builder()
                .messageTopic(MessageTopicEnum.PAID_CALLBACK_ZXD.name())
                .messageKey(CommonUtil.getMessageKey(null))
                .messageBody(messageBody)
                .signature(CommonUtil.hmacMd5Hex(messageBody))
                .status(MessageStatusEnum.SUCCESS.getType())
                .tenantId(Optional.ofNullable(paidCallback.getTenantId()).orElse(UserVoContextHolder.getTenantId()))
                .build();
        messageInfoService.addMessageInfo(messageInfo);
        List<ExcutionSetPaidDTO> paidList = paidCallback.getPaidList();
        List<String> excuteCodeList = paidList.stream().map(ExcutionSetPaidDTO::getExcuteCode).collect(Collectors.toList());
        List<ContractExcutionOrder> excutionOrderList = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE)
                .in(ContractExcutionOrder::getExcuteCode, excuteCodeList));
        if (CollectionUtils.isNotEmpty(excutionOrderList)) {
            Map<String, ContractExcutionOrder> excutionOrderMap = excutionOrderList.stream().collect(Collectors
                    .toMap(ContractExcutionOrder::getExcuteCode, contractExecutionOrder -> contractExecutionOrder));
            paidList.forEach(paid -> {
                BusinessAssert.isTrue(excutionOrderMap.containsKey(paid.getExcuteCode()), McnErrorCode.EXECUTION_NOT_EXISTS, "财务-执行单打款回调，查询不到执行单=" + paid.getExcuteCode());
            });
            for (ExcutionSetPaidDTO paid : paidList) {
                ContractExcutionOrder contractExcutionOrder = excutionOrderMap.get(paid.getExcuteCode());
                boolean result = contractExcutionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(ContractExcutionOrder.class)
                        .set(ContractExcutionOrder::getPaidWay, paid.getPaidWay())
                        .set(ContractExcutionOrder::getAccountId, paid.getAccountId())
                        .set(ContractExcutionOrder::getAccountType, paid.getAccountType())
                        .set(ContractExcutionOrder::getHandlingFeeRate, paid.getHandlingFeeRate())
                        .set(ContractExcutionOrder::getCustomerInvoiceWay, paid.getCustomerInvoiceWay())
                        .set(ContractExcutionOrder::getPaidStarDate, paid.getPaidDate())
                        .set(ContractExcutionOrder::getPaidRemark, paid.getPaidRemark())
                        .set(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.PAID.getCode())
                        .set(ContractExcutionOrder::getUpdateBy, paidCallback.getOperatorId())
                        .set(ContractExcutionOrder::getUpdateName, paidCallback.getOperatorName())
                        .set(ContractExcutionOrder::getUpdateDate, new Date())
                        .eq(ContractExcutionOrder::getId, contractExcutionOrder.getId()));
                if (result) {
                    //操作日志
                    EventPublisher.post(OperateLogEvent.builder().businessId(contractExcutionOrder.getId())
                            .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                            .compare(contractExcutionOrder, contractExcutionOrderMapper.selectById(contractExcutionOrder.getId()))
                            .build());
                }
            }
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean shareAmount(CheckParam checkParam) {
        ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectOne(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getId, checkParam.getId()).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
        BusinessAssert.notNull(contractExcutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        CalculationDevided calculationDevided = calculationDevidedMapper.selectOne(Wrappers.lambdaQuery(CalculationDevided.class)
                .eq(CalculationDevided::getExcutionOrderId, checkParam.getId())
                .eq(CalculationDevided::getIsDelete, NumberCst.ZERO));
        BusinessAssert.notNull(calculationDevided, McnErrorCode.NO_CALCULATION_DEVIDED);
        LambdaUpdateWrapper<CalculationDevided> lambdaUpdateWrapper = Wrappers.lambdaUpdate(CalculationDevided.class);

        if(SettlementMethodEnum.isReceivePayment(calculationDevided.getSettlementMethod())) {
            BusinessAssert.notNull(checkParam.getFinanceShareAmount(), McnErrorCode.PARAM_ERROR, "【财务确认应收金额】必填");
            if(ObjectUtils.defaultIfNull(checkParam.getFinanceShareAmount(), BigDecimal.ZERO)
                    .compareTo(ObjectUtils.defaultIfNull(calculationDevided.getAeReceivableAmount(), BigDecimal.ZERO))  != 0) {
                BusinessAssert.notBlank(checkParam.getFinanceDevidedRemark(), "财务确认应收金额≠AE确认应收金额，请在“财务备注”中进行差异说明！");
            }
            lambdaUpdateWrapper.set(CalculationDevided::getAmountReceivable, checkParam.getFinanceShareAmount())
                    .set(CalculationDevided::getFinanceDevidedAmount, null);
        } else if(SettlementMethodEnum.isRemittance(calculationDevided.getSettlementMethod())) {
            BusinessAssert.notNull(checkParam.getFinanceShareAmount(), McnErrorCode.PARAM_ERROR, "【财务确认分成金额】必填");
            BusinessAssert.notNull(checkParam.getFinanceCulturalTax(), McnErrorCode.PARAM_ERROR, "【财务确认文建税】必填");
            boolean eq1 = ObjectUtils.defaultIfNull(checkParam.getFinanceShareAmount(), BigDecimal.ZERO)
                    .compareTo(ObjectUtils.defaultIfNull(calculationDevided.getAeDevidedAmount(), BigDecimal.ZERO))  != 0;
            boolean eq2 = ObjectUtils.defaultIfNull(checkParam.getFinanceCulturalTax(), BigDecimal.ZERO)
                    .compareTo(ObjectUtils.defaultIfNull(calculationDevided.getAeCulturalTax(), BigDecimal.ZERO))  != 0;
            if(eq1 && eq2) {
                BusinessAssert.notBlank(checkParam.getFinanceDevidedRemark(), "财务确认分成金额≠AE确认分成金额，财务确认文建税≠AE确认文建税，请在“财务备注”中进行差异说明！");
            } else if(eq1) {
                BusinessAssert.notBlank(checkParam.getFinanceDevidedRemark(), "财务确认分成金额≠AE确认分成金额，请在“财务备注”中进行差异说明！");
            } else if(eq2) {
                BusinessAssert.notBlank(checkParam.getFinanceDevidedRemark(), "财务确认文建税≠AE确认文建税，请在“财务备注”中进行差异说明！");
            }
            lambdaUpdateWrapper.set(CalculationDevided::getFinanceDevidedAmount, checkParam.getFinanceShareAmount())
                    .set(CalculationDevided::getAmountReceivable, null);
        }
        BigDecimal handlingFeeRate = null;
        if(AccountTypeEnum.THIRD_PAY_ACCOUNT.getType().equals(checkParam.getAccountType()) && Objects.nonNull(checkParam.getAccountId())) {
            ThirdPayAccount thirdPayAccount = baseInfoClient.getThirdPayById(checkParam.getAccountId()).getObj();
            if(Objects.nonNull(thirdPayAccount)) {
                handlingFeeRate = thirdPayAccount.getHandlingFeeRate();
            }
        }
        lambdaUpdateWrapper.set(CalculationDevided::getFinanceCulturalTax, checkParam.getFinanceCulturalTax())
                .set(CalculationDevided::getFinanceDevidedRemark, checkParam.getFinanceDevidedRemark())
                .set(CalculationDevided::getUpdateBy, UserVoContextHolder.getUserId())
                .set(CalculationDevided::getUpdateName, UserVoContextHolder.getUserName())
                .set(CalculationDevided::getUpdateDate, new Date())
                .eq(CalculationDevided::getId, calculationDevided.getId());
        calculationDevidedMapper.updateByNoStrategy(lambdaUpdateWrapper);

        contractExcutionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(ContractExcutionOrder.class)
                .set(ContractExcutionOrder::getPaidWay, checkParam.getPaidWay())
                .set(ContractExcutionOrder::getCustomerInvoiceWay, checkParam.getCustomerInvoiceWay())
                .set(ContractExcutionOrder::getAccountId, checkParam.getAccountId())
                .set(ContractExcutionOrder::getAccountType, checkParam.getAccountType())
                .set(Objects.nonNull(handlingFeeRate), ContractExcutionOrder::getHandlingFeeRate, handlingFeeRate)
                .set(ContractExcutionOrder::getPaidRemark, checkParam.getPaidRemark())
                .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                .set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                .set(ContractExcutionOrder::getUpdateDate, new Date())
                .eq(ContractExcutionOrder::getId, contractExcutionOrder.getId()));
        return true;
    }

    @Override
    public ExcutionSettleInfoVO getSettleInfoForCharge(Integer chargeType, String chargeSourceCode) {
        FinanceChargeTypeEnum chargeTypeEnum = FinanceChargeTypeEnum.getByType(chargeType);
        ExcutionSettleInfoVO settleInfo = new ExcutionSettleInfoVO();
        switch (chargeTypeEnum) {
            case STAR_DEVIDED_CHARGE:
                settleInfo = contractExcutionOrderMapper.getStarSettle(chargeSourceCode);
                if (settleInfo != null) {
                    setSettleDictsDepartment(settleInfo);
                    setApproval(settleInfo);
                    if (ExcutionOrderTypeEnum.isOutside(settleInfo.getType())) {
                        settleInfo.setAeDevidedAmount(settleInfo.getHandPrice());
                        settleInfo.setSettleTemplate(FinanceSettTemplateEnum.OUTSIDE_EXCUTION_ORDER_TEMPLATE.getType());
                    }
                    if (settleInfo.getType().equals(ExcutionOrderTypeEnum.INSIDE_EXCUTION_ORDER.getType())) {
                        settleInfo.setSettleTemplate(FinanceSettTemplateEnum.INSIDE_EXCUTION_ORDER_TEMPLATE.getType());
                    }
                    /*if(ExcutionOrderTypeEnum.isInside(settleInfo.getType()) && SettlementMethodEnum.isBatchRemittance(settleInfo.getSettlementMethod())) {
                        settleInfo.setDividedRate(this.getDevidedRateWithAd(settleInfo.getDevidedRateInfo()));
                    }*/
                }
                break;
            case YEAR_REBATE_CHARGE:
                settleInfo = annualRebateApprovalMapper.getSettle(chargeSourceCode);
                if (settleInfo != null) {
                    settleInfo.setTitle(chargeTypeEnum.getDesc());
                    settleInfo.setDescription(chargeTypeEnum.getDesc());
                    settleInfo.setSettleTemplate(FinanceSettTemplateEnum.PURCHASE_REBATE_TEMPLATE.getType());
                    settleInfo.setFlowId(approvalFlowService.getFlowId(settleInfo.getId(), ApprovalEnum.ANNUAL_REBATE_APPROVAL.getProcessId()));
                    settleInfo.setFlowIds(approvalFlowService.getStringFlowIds(settleInfo.getId(), ApprovalEnum.ANNUAL_REBATE_APPROVAL.getProcessId()));
                    settleInfo.setCapitalLoanAmount(NumToChineseRMB.number2CNMontrayUnit(settleInfo.getLoanAmount()));
                    setSettleDictsDepartment(settleInfo);
                    setCustomerAccount(settleInfo);
                }
                break;
            case CUSTOMER_REBATE_CHARGE:
                settleInfo = annualRebateApprovalMapper.getCustomerSettle(chargeSourceCode);
                if (settleInfo != null) {
                    settleInfo.setTitle(chargeTypeEnum.getDesc());
                    settleInfo.setDescription(chargeTypeEnum.getDesc());
                    settleInfo.setSettleTemplate(FinanceSettTemplateEnum.PURCHASE_REBATE_TEMPLATE.getType());
                    settleInfo.setFlowId(approvalFlowService.getFlowId(settleInfo.getId(), ApprovalEnum.ANNUAL_REBATE_APPROVAL.getProcessId()));
                    settleInfo.setFlowIds(approvalFlowService.getStringFlowIds(settleInfo.getId(), ApprovalEnum.ANNUAL_REBATE_APPROVAL.getProcessId()));
                    settleInfo.setCapitalLoanAmount(NumToChineseRMB.number2CNMontrayUnit(settleInfo.getLoanAmount()));
                    setSettleDictsDepartment(settleInfo);
                    setCustomerAccount(settleInfo);
                    /*if(ExcutionOrderTypeEnum.isInside(settleInfo.getType()) && SettlementMethodEnum.isBatchRemittance(settleInfo.getSettlementMethod())) {
                        settleInfo.setDividedRate(this.getDevidedRateWithAd(settleInfo.getDevidedRateInfo()));
                    }*/
                }
                break;
            case STAR_PURCHASE_CHARGE:
                settleInfo = contractExcutionOrderMapper.getStarSettle(chargeSourceCode);
                if (settleInfo != null) {
                    setSettleDictsDepartment(settleInfo);
                    setApproval(settleInfo);
                    settleInfo.setAeDevidedAmount(settleInfo.getHandPrice());
                    settleInfo.setSettleTemplate(FinanceSettTemplateEnum.OUTSIDE_EXCUTION_ORDER_TEMPLATE.getType());
                }
                break;
            case INCOME_CONTRACT_CHARGE:
            default:
                ;
        }
        if (Objects.nonNull(settleInfo) && Objects.nonNull(settleInfo.getStarId())) {
            //wms费用版本，红人手机号更改为取联系人手机号
            Long starId = settleInfo.getStarId();
            String starLiaisonPhone = starMonthlySettlementDetailMapper.selectStarLiaisonPhoneByStartId(starId);
            settleInfo.setStarLiaisonPhone(starLiaisonPhone);
        }
        if(Objects.nonNull(settleInfo.getCustomerId())) {
            Map<Long, BaseCustomer> customerMapping = baseInfoClient.getMcnCustomerByIds(Arrays.asList(settleInfo.getCustomerId())).getObj();
            if(CommonUtil.containsKey(customerMapping, settleInfo.getCustomerId())) {
                BaseCustomer baseCustomer = customerMapping.get(settleInfo.getCustomerId());
                settleInfo.setCustomerSignSubject(baseCustomer.getCustomerNameC());
            }
        }
        return settleInfo;
    }

    /**
     * 设置客户账户信息
     */
    private void setCustomerAccount(ExcutionSettleInfoVO settleInfo) {
        BaseCustomerAccountVO customerAccountVO = baseInfoClient.getCustomerAccountById(settleInfo.getAccountId()).getObj();
        settleInfo.setAccountName(customerAccountVO.getAccountName());
        settleInfo.setAccountBank(customerAccountVO.getBankName());
        settleInfo.setAccountNumber(customerAccountVO.getCardNumber());
        settleInfo.setAccountBranchBank(customerAccountVO.getBankNameBranch());
    }

    /**
     * 设置审批流信息
     */
    public void setApproval(ExcutionSettleInfoVO settleInfo) {
        Long processId = null;
        if (settleInfo.getType().equals(ExcutionOrderTypeEnum.INSIDE_EXCUTION_ORDER.getType())) {
            processId = ApprovalEnum.EXECUTION_INSIDE_STAR.getProcessId();
        }
        if (ExcutionOrderTypeEnum.isOutside(settleInfo.getType())) {
            processId = ApprovalEnum.EXCUTION_OUTSIDE_STAR.getProcessId();
        }
        Long flowId = approvalFlowService.getFlowId(settleInfo.getId(), processId);
        String stringFlowIds = approvalFlowService.getStringFlowIds(settleInfo.getId(), processId);
        settleInfo.setFlowId(flowId);
        settleInfo.setFlowIds(stringFlowIds);
    }

    /**
     * 设置数据字典
     */
    private void setSettleDicts(ExcutionSettleInfoVO settleInfo) {
        DescByCodeDTO descByCodeDTO = new DescByCodeDTO();
        descByCodeDTO.setProfileCodes(Collections.singletonList("SubjectOfContract"));
        descByCodeDTO.setDictsCodes(Arrays.asList(settleInfo.getCompanyContractSubject(), settleInfo.getHeader()));
        Map<String, String> dictsMap = baseInfoClient.getDescByCode(descByCodeDTO).getObj();
        if (StringUtils.isNotBlank(settleInfo.getCompanyContractSubject())) {
            settleInfo.setCompanyContractSubjectName(
                    dictsMap.get("SubjectOfContract;" + settleInfo.getCompanyContractSubject()));
        }
    }

    /**
     * 设置数据字典、创建人部门名称
     */
    private void setSettleDictsDepartment(ExcutionSettleInfoVO settleInfo) {
        setSettleDicts(settleInfo);
        settleInfo.setCreatorDepartment(this.getDepartment(settleInfo.getCreateBy()));
    }

    @Override
    public ContractExcutionOrder getById(Long id) {
        return contractExcutionOrderMapper.selectById(id);
    }

    @Override
    public Page<CusExcutionOrderVO> getCusExcutionOrder(McnPage<CusExcutionOrderVO> mcnPage, Long customerId) {
        /**
         * 查询客户关联执行单
         */
        Page<CusExcutionOrderVO> cusExcutionOrderPage = contractExcutionOrderMapper.getCusExcutionOrder(mcnPage, customerId, ApprovalEnum.getExecutionOrderProcessIds());

        List<CusExcutionOrderVO> excutionOrderList = cusExcutionOrderPage.getRecords();
        if (CollectionUtil.isNotEmpty(excutionOrderList)) {
            List<Long> flowList = excutionOrderList.stream().map(CusExcutionOrderVO::getFlowId).filter(Objects::nonNull).collect(Collectors.toList());
            // 审批名称
            JSONObject flowMapping = null;
            if (flowList.size() > 0) {
                flowMapping = approvalFlowService.getFlowStatus(flowList);
            }
            JSONObject finalFlowMapping = flowMapping;
            excutionOrderList.forEach(contract -> {
                if (Objects.nonNull(finalFlowMapping) && finalFlowMapping.size() > 0 && Objects.nonNull(contract.getFlowId())) {
                    contract.setFlowStatusName(finalFlowMapping.getString(contract.getFlowId().toString()));
                }
                contract.setApprovalStatusName(ExcutionApprovalStatusEnum.getStatusName(contract.getApprovalStatus()));
            });
        }
        return cusExcutionOrderPage;
    }

    /**
     * 根据执行单号获取执行单总金额
     *
     * @param executeCode 执行单号
     * @return {@link BigDecimal}
     */
    @Override
    public BigDecimal getActualQuotedPrice(String executeCode) {
        BigDecimal actualQuotedPrice = null;
        ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectOne(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getExcuteCode, executeCode)
                .eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE));
        if (Objects.nonNull(contractExcutionOrder)) {
            actualQuotedPrice = contractExcutionOrder.getActualQuotedPrice();
        }
        return actualQuotedPrice;
    }

    /**
     * AE执行单列表
     *
     * @param mcnPage
     * @param excutionOrderSearchDTO
     * @return
     */
    @Override
    public Page<ExcutionOrderVO> getAePage(McnPage<ExcutionOrderVO> mcnPage,
                                            ExcutionOrderSearchDTO excutionOrderSearchDTO) {
        mcnPage.setPageNum(excutionOrderSearchDTO.getPageNum());
        mcnPage.setPageSize(excutionOrderSearchDTO.getPageSize());
        Page<ExcutionOrderVO> page = contractExcutionOrderMapper.getAePage(mcnPage, excutionOrderSearchDTO);
        List<ExcutionOrderVO> records = page.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            /**
             * 查询客户名称
             */
            List<Long> customerIds = records.stream().map(ExcutionOrderVO::getCustomerId).collect(Collectors.toList());
            Map<Long, BaseCustomer> customerMapping = Objects.requireNonNull(baseInfoClient.getMcnCustomerByIds(customerIds)).getObj();
            List<String> brandCodes = records.stream().map(ExcutionOrderVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            records.forEach(record -> {
                if(Objects.nonNull(record.getPaybackStatus())){
                    record.setApprovalStatusName(ExcutionApprovalStatusEnum.getStatusName(record.getApprovalStatus()));
                    record.setPaybackStatusName(PaybackStatusEnum.getStatusName(record.getPaybackStatus()));
                    record.setContractApprovalStatusName(ApprovalStatusEnum.getStatusName(record.getContractApprovalStatus()));
                    record.setContractPaybackStatusName(PaybackStatusEnum.getStatusName(record.getContractPaybackStatus()));
                    record.setRebateSettleStatusName(CommonSettleStatusEnum.getStatusName(record.getRebateSettleStatus()));
                }
                if (customerMapping.containsKey(record.getCustomerId())) {
                    record.setCustomerName(customerMapping.get(record.getCustomerId()).getCustomerNameC());
                }
                if(brandMap.containsKey(record.getBrandName())) {
                    record.setBrandNameN(brandMap.get(record.getBrandName()));
                }
            });
        }
        return page;
    }

    @Override
    public List<ExcutionOrderVO> getExportCommissionData(ExcutionOrderSearchDTO excutionOrderSearchDTO) {
        return contractExcutionOrderMapper.getAePage(new Page<>(1, -1L, false), excutionOrderSearchDTO).getRecords();
    }

    /**
     * 分页查询红人返点执行单
     *
     * @param mcnPage
     * @param excutionOrderSearchDTO
     * @return
     */
    @Override
    public Page<StarRebateExcutionOrderVO> getStarRebatePage(McnPage<ExcutionOrderVO> mcnPage, ExcutionOrderSearchDTO excutionOrderSearchDTO) {
        mcnPage.setPageNum(excutionOrderSearchDTO.getPageNum());
        mcnPage.setPageSize(excutionOrderSearchDTO.getPageSize());
        excutionOrderSearchDTO.setAlias("ceo.");
        Page<StarRebateExcutionOrderVO> page = contractExcutionOrderMapper.getStarRebatePage(mcnPage, excutionOrderSearchDTO);
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            //字典翻译
            DictTranslationUtils.translation(() -> DictStream.of(DictStream.map(DictTypeCst.RELEASE_TYPE, StarRebateExcutionOrderVO::getPublishType, StarRebateExcutionOrderVO::setPublishType)
                     ), (profileCodes, dictsCodes) -> baseInfoClient.getDescByCode(new DescByCodeDTO(profileCodes, dictsCodes)).getObj(), page.getRecords()
             );
            //查询品牌
            List<String> brandCodes = page.getRecords().stream().map(StarRebateExcutionOrderVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
            //查询平台名称
            List<Long> starPlatInfoIds = page.getRecords().stream().map(StarRebateExcutionOrderVO::getStarPlatformInfoId).collect(Collectors.toList());
            List<StarPlatInfoVO> starInfoList = starPlatformInfoService.getByIds(starPlatInfoIds);
            Map<Long, StarPlatInfoVO> starPlatInfoVoMap = starInfoList.stream().collect(Collectors.toMap(StarPlatInfoVO::getId, starPlatInfoVO -> starPlatInfoVO));
            Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.PUBLISHING_PLATFORM);
            page.getRecords().forEach(record -> {
                if (CommonUtil.containsKey(starPlatInfoVoMap, record.getStarPlatformInfoId())) {
                    StarPlatInfoVO starPlatformInfo = starPlatInfoVoMap.get(record.getStarPlatformInfoId());
                    record.setPlatformId(starPlatformInfo.getPlatformId());
                    record.setPlatformName(starPlatInfoVoMap.get(record.getStarPlatformInfoId()).getPlatformName());
                    record.setPlatNickName(starPlatformInfo.getPlatNickName());
                    //赋值平台名称 这个比较特殊 改字段了因此需要单独处理
                    if (StringUtils.isNotBlank(record.getPublishForm())) {
                        record.setPublishForm(CommonUtil.getMapValue(secondlevelDictMap.get(record.getPlatformId()), record.getPublishForm()));
                    }
                }
                if(brandMap.containsKey(record.getBrandName())) {
                    record.setBrandNameN(brandMap.get(record.getBrandName()));
                }
            });
        }
        return page;
    }

    @Override
    public Page<AnnualRebateExcutionOrderVO> getAnnualRebatePage(McnPage<ExcutionOrderVO> mcnPage, ExcutionOrderSearchDTO excutionOrderSearchDTO) {
        mcnPage.setPageNum(excutionOrderSearchDTO.getPageNum());
        mcnPage.setPageSize(excutionOrderSearchDTO.getPageSize());
        excutionOrderSearchDTO.setAlias("ceo.");
        Page<AnnualRebateExcutionOrderVO> page = contractExcutionOrderMapper.getAnnualRebatePage(mcnPage, excutionOrderSearchDTO);
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            page.getRecords().forEach(record -> {
                record.setRebateSettleStatusName(CommonSettleStatusEnum.getStatusName(record.getRebateSettleStatus()));
                record.setApprovalStatusName(ExcutionApprovalStatusEnum.getStatusName(record.getApprovalStatus()));
                record.setPaybackStatusName(PaybackStatusEnum.getStatusName(record.getPayBackStatus()));
                record.setIncomeContractTypeName(IncomeContractTypeEnum.getContractTypeName(record.getIncomeContractType()));
            });
        }
        return page;
    }

    /**
     * 供AE提成单查询执行单列表
     *
     * @param aeQueryExcutionOrderDTO
     * @return
     */
    @Override
    public List<Long> getContractExcutionOrderByCondition(AeQueryExcutionOrderDTO aeQueryExcutionOrderDTO) {
        return contractExcutionOrderMapper.getContractExcutionOrderByCondition(aeQueryExcutionOrderDTO);
    }

    /**
     * 批量查询执行单
     *
     * @param ids
     * @return
     */
    @Override
    public List<ContractExcutionOrder> getAllByIds(List<Long> ids) {
        List<ContractExcutionOrder> list = null;
        if (Objects.nonNull(ids)) {
            list = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class).in(ContractExcutionOrder::getId, ids));
        }
        return list;
    }

    @Override
    public Integer batchUpdateSettleStatus(List<Long> excutionOrderIds, Integer commissionSettleStatus) {
        if (CollectionUtil.isEmpty(excutionOrderIds) || commissionSettleStatus == null) {
            throw new BusinessException(McnErrorCode.PARAM_ERROR);
        }
        return contractExcutionOrderMapper.batchUpdateSettleStatus(excutionOrderIds, commissionSettleStatus);
    }

    @Override
    public void verifyFormalExcutionOrder(Long contractId, boolean isFromExcutionOrder, List<ContractExcutionOrder> excutionOrders) {
        if (isFromExcutionOrder || CollectionUtils.isEmpty(excutionOrders)) {
            return;
        }
        verifyPlatformOrderNumber(contractId, excutionOrders);
        /**
         *新建收入合同，编辑收入合同，补充协议关联执行单保存时，校验：”新建执行单所关联的意向单没有关联过其他执行单“，有的话就不能保存
         * */
        List<Long> intentionOrder = excutionOrders.stream().map(ContractExcutionOrder::getIntentionOrderId).collect(Collectors.toList());
        List<DocIntentionOrder> docIntentionOrders = intentionOrderMapper.selectList(new QueryWrapper<DocIntentionOrder>().lambda().in(DocIntentionOrder::getId, intentionOrder));
        Map<Long, DocIntentionOrder> intentionOrderMap = docIntentionOrders.stream().collect(Collectors.toMap(DocIntentionOrder::getId, x -> x, (x, y) -> x));
        for (ContractExcutionOrder item:excutionOrders){
            if (Objects.nonNull(item.getIntentionOrderId())){
                DocIntentionOrder docIntentionOrder =intentionOrderMap.get(item.getIntentionOrderId());
                if (StringUtils.isNotEmpty(docIntentionOrder.getIncomeContractCode())){
                    if (!item.getIncomeContractCode().equals(docIntentionOrder.getIncomeContractCode())) {
                        throw new BusinessException(McnErrorCode.INTENT_HAS_ALREADY_BEEN_LINKED_BY_OTHER);
                    }
                    if (StringUtils.isNotEmpty(docIntentionOrder.getExcutionOrderCode())) {
                        if (!item.getExcuteCode().equals(docIntentionOrder.getExcutionOrderCode())) {
                            throw new BusinessException(McnErrorCode.INTENT_HAS_ALREADY_BEEN_LINKED_BY_OTHER);
                        }
                    }
                }
            }
        }
    }

    /**
     * 校验平台订单号
     * @param contractId
     * @param excutionOrders
     */
    @Override
    public void verifyPlatformOrderNumber(Long contractId, List<ContractExcutionOrder> excutionOrders) {
        //如果是形式合同
        List<ContractExcutionOrder> verifyOrders = CommonUtil.defaultList(excutionOrders).stream()
                .filter(item -> !ExcutionApprovalStatusEnum.INVALID.getCode().equals(item.getApprovalStatus())).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(verifyOrders)) {
            return;
        }
        List<String> platformOrderCodeList = new ArrayList<>(verifyOrders.size());
        List<Long> excutionOrderIds = new ArrayList<>(verifyOrders.size());
        verifyOrders.forEach(item -> {
            if(StringUtils.isNotBlank(item.getPlatformOrderNumber())) {
                item.setPlatformOrderCode(item.getPlatformOrderNumber());
            }
            OrderPlatformEnum orderPlatformEnum = OrderPlatformEnum.toEnum(item.getOrderPlatform());
            if (item.getPlatformReport() != null && item.getPlatformReport()) {
                BusinessAssert.notBlank(item.getPlatformOrderCode(), McnErrorCode.PARAM_ERROR, "平台订单号不能为空");
                if (Objects.nonNull(orderPlatformEnum)) {
                    BusinessAssert.isTrue(orderPlatformEnum.meetLength(item.getPlatformOrderCode()), "平台订单号长度错误，请检查后重试");
                    BusinessAssert.isTrue(orderPlatformEnum.verifyFormat(item.getPlatformOrderCode()), "平台订单号录入错误！");
                }
                if (!platformOrderCodeList.contains(item.getPlatformOrderCode())) {
                    platformOrderCodeList.add(item.getPlatformOrderCode());
                }else{
                    throw new BusinessException(McnErrorCode.PLATFORM_ORDER_NUMBER_REPEAT);
                }
                if (contractId != null) {
                    excutionOrderIds.add(item.getId());
                }
            }

        });
        if (CollectionUtils.isNotEmpty(platformOrderCodeList)) {
            BusinessAssert.isTrue(contractExcutionOrderMapper.selectCount(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .in(ContractExcutionOrder::getPlatformOrderCode, platformOrderCodeList)
                    .eq(ContractExcutionOrder::getIsDelete, 0)
                    .notIn(CollectionUtils.isNotEmpty(excutionOrderIds), ContractExcutionOrder::getId, excutionOrderIds)
                    .ne(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.INVALID.getCode()))
                    == 0, McnErrorCode.DATA_EXISTED, "平台订单号已存在");
        }
    }

    @Override
    public void changeExcutionOrders(Long contractId, List<ContractExcutionOrder> excutionOrders) {
        List<ContractExcutionOrder> beforeContractExcutionOrders = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getIncomeContractId, contractId)
                .eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
        if(CollectionUtils.isEmpty(beforeContractExcutionOrders)) {
            return;
        }
        List<ContractExcutionOrder> deleteExcutionOrderList = null;
        if (CollectionUtils.isEmpty(excutionOrders)) {
            deleteExcutionOrderList = beforeContractExcutionOrders;
        } else {
            List<Long> excutionOrderIds = excutionOrders.stream().map(ContractExcutionOrder::getId).filter(Objects::nonNull).collect(Collectors.toList());
            deleteExcutionOrderList = beforeContractExcutionOrders.stream().filter(a -> !excutionOrderIds.contains(a.getId())).collect(Collectors.toList());
        }
        if (CollectionUtils.isNotEmpty(deleteExcutionOrderList)) {
            this.verifyStatusOnDelete(deleteExcutionOrderList);
            ContractExcutionOrder deleteEntity = new ContractExcutionOrder();
            deleteEntity.setIsDelete(NumberCst.ONE);
            List<Long> deleteIds = deleteExcutionOrderList.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
            contractExcutionOrderMapper.update(deleteEntity, Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .in(ContractExcutionOrder::getId, deleteIds).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
            //解除意向单关联
            intentionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(DocIntentionOrder.class)
                    .eq(DocIntentionOrder::getIncomeContractId, contractId)
                    .in(DocIntentionOrder::getExcutionOrderId, deleteIds)
                    .set(DocIntentionOrder::getIncomeContractId, null)
                    .set(DocIntentionOrder::getIncomeContractCode, null)
                    .set(DocIntentionOrder::getExcutionOrderId, null)
                    .set(DocIntentionOrder::getExcutionOrderCode, null)
                    .set(DocIntentionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(DocIntentionOrder::getUpdateName, UserVoContextHolder.getUserName())
                    .set(DocIntentionOrder::getUpdateDate, new Date()));
        }
    }

    /**
     * 合同删除执行单时校验
     * @param excutionorders
     */
    private void verifyStatusOnDelete(List<ContractExcutionOrder> excutionorders) {
        long count = CommonUtil.defaultList(excutionorders).stream().filter(e -> !ExcutionApprovalStatusEnum.anyMatch(e.getApprovalStatus(), ExcutionApprovalStatusEnum.UN_EXECUTE, ExcutionApprovalStatusEnum.INVALID)).count();
        BusinessAssert.isTrue(count == 0, "仅允许删除待发布、已作废状态的执行单！");
    }

    @Override
    public List<String> getProductName() {
        List<ContractExcutionOrder> excutionOrderList = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getIsDelete, 0));
        return excutionOrderList.stream().map(ContractExcutionOrder::getProductName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
    }

    /**
     * 导入审批Excel-奇葩需求性能待优化
     *
     * @param inputList {@link List<   ExcutionOrderBatchConfirmInputDTO   >}
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String financeBatchConfirm(List<ExcutionOrderBatchConfirmInputDTO> inputList) {
        BusinessAssert.notEmpty(inputList, McnErrorCode.IMPORT_CONTENT_EMPTY);
        Map<String, AccountInfoVO> accountInfoVoMap = CommonUtil.defaultList(baseInfoClient.getThirdPayAllAccount().getObj())
                .stream().collect(Collectors.toMap(AccountInfoVO::getAccountName, accountInfoVO -> accountInfoVO, (v1, v2) -> v1));
        //1、参数校验
        List<ExcutionOrderBatchConfirmOutputDTO> outputList = this.verifyImportFinanceConfirm(accountInfoVoMap, inputList);
        //2、补全审批信息
        this.approvalInfoForConfirmDevided(outputList);
        // 3、处理数据
        List<ExcutionOrderBatchConfirmOutputDTO> errorList = outputList.stream().filter(data -> StringUtils.isNotBlank(data.getFailedReason())).collect(Collectors.toList());
        boolean failFlag = CollectionUtils.isNotEmpty(errorList);
        if (!failFlag && CollectionUtils.isNotEmpty(outputList)) {
            Map<Long, ApprovalOperationDTO> approvalMap = new HashMap<>(outputList.size());
            this.verifyAndBatchConfirmDevided(outputList, approvalMap);
            List<ApprovalOperationDTO> approvalList = approvalMap.entrySet().stream().map(e -> e.getValue()).collect(Collectors.toList());
            Map<Long, String> approvalResultMap = CommonUtil.defaultList(processClient.approvalChange(approvalList).getObj()).stream().filter(d -> !d.isSuccess())
                    .collect(Collectors.toMap(ApprovalOperationVO::getApprovalId, v -> StringUtils.defaultString(v.getMessage(), "审批异常-未给失败原因")));
            if (MapUtils.isNotEmpty(approvalResultMap)) {
                failFlag = true;
                outputList.forEach(e -> {
                    if (approvalResultMap.containsKey(e.getApprovalId())) {
                        StringBuffer sb = new StringBuffer();
                        if (StringUtils.isNotBlank(e.getFailedReason())) {
                            sb.append(e.getFailedReason()).append(SEPARATOR);
                        }
                        sb.append(approvalResultMap.get(e.getApprovalId()));
                        e.setFailedReason(sb.toString());
                    }
                });
            }
        }
        if (failFlag) {
            return generateDownloadFiledId(ImportExcelEnum.FINANCE_BATCH_CONFIRM_DEVIDED.getFileId(), outputList);
        }
        return "";
    }

    @Override
    public String financeBatchApproval(List<ExcutionOrderBatchApprovalInputDTO> inputList) {
        BusinessAssert.notEmpty(inputList, McnErrorCode.IMPORT_CONTENT_EMPTY);
        //1、校验参数格式
        List<ExcutionOrderBatchApprovalOutputDTO> outputList = inputList.stream().map(e -> {
            ExcutionOrderBatchApprovalOutputDTO outputDTO = new ExcutionOrderBatchApprovalOutputDTO();
            BeanUtils.copyProperties(e, outputDTO);
            outputDTO.setFailedReason(ValidatorUtil.getJointValidateResult(outputDTO, SeparatorCst.LINE_BREAK));
            if(StringUtils.equalsAny(e.getApprovalResult(), "拒绝", "驳回") && StringUtils.isBlank(e.getApprovalNote())) {
                outputDTO.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, outputDTO.getFailedReason(), "【审批意见】必填！"));
            }
            return outputDTO;
        }).collect(Collectors.toList());
        //2、校验唯一性
        List<String> repeatedVouchers = outputList.stream().filter(e -> StringUtils.isNotBlank(e.getExcuteCode()))
                .collect(Collectors.groupingBy(e -> e.getExcuteCode(), Collectors.counting()))
                .entrySet().stream().filter(e -> e.getValue().longValue() > 1L).map(Map.Entry::getKey).collect(Collectors.toList());
        outputList.forEach(e -> {
            if (repeatedVouchers.contains(e.getExcuteCode())) {
                e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "正式执行单单号重复！"));
            }
        });
        //3、校验系统数据匹配校验
        List<String> excuteCodeList = outputList.stream().map(ExcutionOrderBatchApprovalOutputDTO::getExcuteCode).distinct().collect(Collectors.toList());
        Map<String, ContractExcutionOrder> contractExcutionOrderMap = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(excuteCodeList), () ->
            contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO).in(ContractExcutionOrder::getExcuteCode, excuteCodeList))
                    .stream().collect(Collectors.toMap(ContractExcutionOrder::getExcuteCode, Function.identity())) , Collections.EMPTY_MAP);
        outputList.forEach(e -> {
            if (!contractExcutionOrderMap.containsKey(e.getExcuteCode())) {
                e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "正式执行单查询不到！"));
            } else {
                ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMap.get(e.getExcuteCode());
                if(!ExcutionApprovalStatusEnum.isApproval(contractExcutionOrder.getApprovalStatus())) {
                    e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "非审批中，不允许操作！"));
                }
                e.setId(contractExcutionOrder.getId());
                e.setApprovalStatus(contractExcutionOrder.getApprovalStatus());
            }
        });
        //补全审批信息
        this.approvalInfoForBatchApproval(outputList);
        List<ExcutionOrderBatchApprovalOutputDTO> successList = outputList.stream().filter(e -> StringUtils.isBlank(e.getFailedReason())).collect(Collectors.toList());
        Map<String, List<ExcutionOrderBatchApprovalOutputDTO>> successMap = successList.stream().collect(Collectors.groupingBy(ExcutionOrderBatchApprovalOutputDTO::getApprovalResult));
        if (MapUtils.isNotEmpty(successMap)) {
            List<ApprovalOperationDTO> approvalList = new ArrayList<>();
            List<CompletableFuture> completableFutureList = new ArrayList<>();
            for(Map.Entry<String, List<ExcutionOrderBatchApprovalOutputDTO>> entry : successMap.entrySet()) {
                if(StringUtils.equalsAny(entry.getKey(), "通过", "拒绝")) {
                    entry.getValue().forEach(e -> {
                        if(Objects.nonNull(e.getApprovalId())) {
                            ApprovalOperationDTO approvalOperationDTO = new ApprovalOperationDTO();
                            approvalOperationDTO.setApprovalId(e.getApprovalId());
                            approvalOperationDTO.setUserId(UserVoContextHolder.getUserId());
                            approvalOperationDTO.setUserName(UserVoContextHolder.getUserName());
                            approvalOperationDTO.setApprovalFlag("通过".equals(entry.getKey()));
                            approvalOperationDTO.setRemark(e.getApprovalNote());
                            approvalList.add(approvalOperationDTO);
                        }
                    });
                } else if("驳回".equals(entry.getKey())) {
                    entry.getValue().forEach(e -> {
                        if(Objects.nonNull(e.getApprovalId())) {
                            completableFutureList.add(SmartCompletableFuture.runAsync(() -> {
                                        try {
                                            processClient.approvalRejected(e.getApprovalId(), UserVoContextHolder.getUserId(), UserVoContextHolder.getUserName(), e.getApprovalNote());
                                        } catch (Exception exception) {
                                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), exception.getMessage()));
                                        }
                                    }
                            ));
                        }
                    });
                    if(CollectionUtils.isNotEmpty(completableFutureList)) {
                        SmartCompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[]{})).join();
                    }
                }
            }
            if(CollectionUtils.isNotEmpty(approvalList)) {
                List<ApprovalOperationVO> approvalResultList = processClient.approvalChange(approvalList).getObj();
                Map<Long, String> approvalResultMap = approvalResultList.stream().filter(d -> !d.isSuccess())
                        .collect(Collectors.toMap(k -> k.getApprovalId(), v -> StringUtils.defaultString(v.getMessage(), "审批异常-未给失败原因")));
                if(MapUtils.isNotEmpty(approvalResultMap)) {
                    Map<Long, ExcutionOrderBatchApprovalOutputDTO> tempMap = outputList.stream().filter(e -> Objects.nonNull(e.getApprovalId()) && StringUtils.isBlank(e.getFailedReason()))
                            .collect(Collectors.toMap(k -> k.getApprovalId(), Function.identity()));
                    approvalResultMap.entrySet().forEach(e -> {
                        if(CommonUtil.containsKey(tempMap, e.getKey())) {
                            ExcutionOrderBatchApprovalOutputDTO outputDTO = tempMap.get(e.getKey());
                            outputDTO.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, outputDTO.getFailedReason(), "审批异常-" + e.getValue()));
                        }
                    });
                }
            }
        }
        List<ExcutionOrderBatchApprovalOutputDTO> failedList = outputList.stream().filter(e -> StringUtils.isNotBlank(e.getFailedReason())).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(failedList)) {
            return generateDownloadFiledId(ImportExcelEnum.EXECUTION_BATCH_APPROVAL.getFileId(), failedList);
        }
        return null;
    }

    private  <T> String generateDownloadFiledId(String fileId, T data) {

        stringRedisTemplate.opsForValue().set(McnConstant.CACHE_PRIFIX + fileId, JSONObject.toJSONString(data), 30, TimeUnit.MINUTES);
        return fileId;
    }

    private void verifyAndBatchConfirmDevided(List<ExcutionOrderBatchConfirmOutputDTO> outputList, Map<Long, ApprovalOperationDTO> approvalMap) {
        List<CompletableFuture> completableFutureList = new ArrayList<>(outputList.size()/NumberCst.THREE.intValue()+1);
        Lists.partition(outputList, NumberCst.THREE).forEach(subList -> {
            completableFutureList.add(SmartCompletableFuture.runAsync(() -> {
                for (ExcutionOrderBatchConfirmOutputDTO e : subList) {
                    ApprovalOperationDTO approvalOperationDTO = new ApprovalOperationDTO();
                    approvalOperationDTO.setApprovalId(e.getApprovalId());
                    approvalOperationDTO.setUserId(UserVoContextHolder.getUserId());
                    approvalOperationDTO.setUserName(UserVoContextHolder.getUserName());
                    approvalOperationDTO.setApprovalFlag(true);
                    ContractExcutionOrder updateContractExcutionOrder = new ContractExcutionOrder();
                    updateContractExcutionOrder.setId(e.getId());
                    if (McnConstant.INOVICE_WAY_ISSUED.equals(e.getCustomerInvoiceWay())) {
                        updateContractExcutionOrder.setCustomerInvoiceWay(1);
                    } else if (McnConstant.INOVICE_WAY_AFTER.equals(e.getCustomerInvoiceWay())) {
                        updateContractExcutionOrder.setCustomerInvoiceWay(3);
                    }
                    if (Objects.nonNull(e.getAccountInfoVO())) {
                        updateContractExcutionOrder.setAccountId(e.getAccountInfoVO().getAccountId());
                        updateContractExcutionOrder.setAccountType(e.getAccountInfoVO().getAccountType());
                        updateContractExcutionOrder.setHandlingFeeRate(e.getAccountInfoVO().getHandlingFeeRate());
                    }
                    updateContractExcutionOrder.setPaidWay(e.getPaidWay());
                    contractExcutionOrderMapper.updateById(updateContractExcutionOrder);
                    if (Objects.nonNull(e.getCalculationDevided())) {
                        CalculationDevided cd = e.getCalculationDevided();
                        JSONObject paramJsonObejct = new JSONObject(4);
                        LambdaUpdateWrapper<CalculationDevided> lambdaUpdateWrapper = Wrappers.lambdaUpdate(CalculationDevided.class);
                        if(SettlementMethodEnum.isRemittance(cd.getSettlementMethod())) {
                            lambdaUpdateWrapper.set(CalculationDevided::getFinanceDevidedAmount, e.getFinanceDevidedAmount())
                                    .set(CalculationDevided::getFinanceCulturalTax, e.getFinanceCulturalTax())
                                    .set(CalculationDevided::getAmountReceivable, null);
                            paramJsonObejct.put("financeDevidedAmount", ObjectUtils.defaultIfNull(e.getFinanceDevidedAmount(), BigDecimal.ZERO));
                        } else if(SettlementMethodEnum.isReceivePayment(cd.getSettlementMethod())) {
                            lambdaUpdateWrapper.set(CalculationDevided::getAmountReceivable, e.getAmountReceivable())
                                    .set(CalculationDevided::getFinanceDevidedAmount, null)
                                    .set(CalculationDevided::getFinanceCulturalTax, null);
                            paramJsonObejct.put("financeDevidedAmount", BigDecimal.ZERO);
                        }
                        //更新计算分成
                        calculationDevidedMapper.updateByNoStrategy(lambdaUpdateWrapper
                                .set(CalculationDevided::getFinanceDevidedRemark, e.getFinanceDevidedRemark())
                                .set(CalculationDevided::getUpdateBy, UserVoContextHolder.getUserId())
                                .set(CalculationDevided::getUpdateName, UserVoContextHolder.getUserName())
                                .set(CalculationDevided::getUpdateDate, new Date())
                                .eq(CalculationDevided::getId, cd.getId()));
                        //执行单新版审批流-无财务复核节点-则财务审批节点传参
                        approvalOperationDTO.setParameter(paramJsonObejct.toJSONString());
                    }
                    approvalOperationDTO.setRemark(approvalOperationDTO.isApprovalFlag() ? "同意" : "拒绝");
                    approvalMap.putIfAbsent(approvalOperationDTO.getApprovalId(), approvalOperationDTO);
                }
            }));
            SmartCompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[]{})).join();
        });

    }

    @Override
    public void excelDownload(HttpServletResponse response, String fileId) {
        ImportExcelEnum excelEnum = ImportExcelEnum.toEnum(fileId);
        BusinessAssert.notNull(excelEnum, McnErrorCode.EXPORT_FILE_ID_ILLEGAL);
        // 根据FileId判断导出类型
        String excelContent = CommonUtil.defaultIfEmpty(stringRedisTemplate.opsForValue().get(McnConstant.CACHE_PRIFIX + fileId));
        List<ExcutionOrderBatchConfirmOutputDTO> outputList =
                JSONObject.parseObject(excelContent, new TypeReference<List<ExcutionOrderBatchConfirmOutputDTO>>() {
                });

        BusinessAssert.notEmpty(outputList, McnErrorCode.EXPORT_HAS_NO_DATA);
        try {
            String title = null;
            switch (excelEnum) {
                case FINANCE_BATCH_CONFIRM_DEVIDED:
                    title = "执行单-财务批量审核失败原因";
                    break;
                case EXECUTION_BATCH_APPROVAL:
                    title = "执行单-财务批量复核失败原因";
                    break;
                default:
                    break;
            }
            if (StringUtils.isNotBlank(title)) {
                ExcelUtils.exportExcel(outputList, title, ExcutionOrderBatchConfirmOutputDTO.class, title + ".xlsx", response);
                stringRedisTemplate.delete(McnConstant.CACHE_PRIFIX + fileId);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public List<StarPurchaseYearFrameVO> getStarPurchaseContract() {
        List<YearFrameContract> dataList = yearFrameContractMapper.getYearFrameContract(null, null);
        if (CollectionUtils.isEmpty(dataList)) {
            return new ArrayList<>(0);
        }
        List<Long> customerIdList = dataList.stream().filter(e -> NumberCst.ONE.equals(e.getTargetType())).map(YearFrameContract::getCustomerId).distinct().collect(Collectors.toList());
        Map<Long, BaseCustomer> customerMapping = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(customerIdList), () -> Objects.requireNonNull(baseInfoClient.getMcnCustomerByIds(customerIdList)).getObj(), Collections.EMPTY_MAP);
        List<Long> starIdList = dataList.stream().filter(e -> NumberCst.TWO.equals(e.getTargetType())).map(YearFrameContract::getCustomerId).distinct().collect(Collectors.toList());
        List<StarBasicData> starList = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(starIdList), () -> starBasicDataMapper.selectBatchIds(starIdList), null);
        Map<Long, String> starMap = CommonUtil.defaultList(starList).stream().collect(Collectors.toMap(k -> k.getId(), v -> v.getStarNickname()));

        List<StarPurchaseYearFrameVO> voList = new ArrayList<>(dataList.size());
        List<String> dictProfileList = new ArrayList<>(Collections.singletonList("yearFrameContract"));
        List<String> dictList = dataList.stream().map(YearFrameContract::getContractType).distinct().collect(Collectors.toList());
        Map<String, String> dictMapping = Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO().setDictsCodes(dictList).setProfileCodes(dictProfileList))).getObj();
        dataList.forEach(data -> {
            StarPurchaseYearFrameVO vo = new StarPurchaseYearFrameVO();
            BeanUtils.copyProperties(data, vo);
            if (MapUtils.isNotEmpty(dictMapping)) {
                vo.setContractType(dictMapping.get(dictProfileList.get(0) + SeparatorCst.SEMICOLON + data.getContractType()));
            }
            if(NumberCst.ONE.equals(data.getTargetType())) {
                BaseCustomer customer = customerMapping.get(data.getCustomerId());
                vo.setCustomerName(Objects.nonNull(customer) ? customer.getCustomerNameC() : "");
            } else if(NumberCst.TWO.equals(data.getTargetType())) {
                vo.setCustomerName(starMap.get(data.getCustomerId()));
            }
            voList.add(vo);
        });
        return voList;
    }

    @Override
    public List<AssociatedPurchase> getPurchaseContract(Long incomeContractId) {
        List<AssociatedPurchase> list = new ArrayList<>();
        IncomeContract incomeContract = incomeContractService.selectById(incomeContractId);
        if (null != incomeContract) {
            list = purchaseContractMapper.getPurchaseContract(incomeContract.getContractCode());
        }
        return list;
    }

    @Override
    public List<StarRebateExcutionOrderVO> getByYearCodeOfStarRebate(String yearContractCode) {
        List<ContractExcutionOrder> executionOrders = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getYearCode, yearContractCode)
                .eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE)
                .notIn(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.PAID.getCode(), ExcutionApprovalStatusEnum.INVALID.getCode())
        );
        if (CollectionUtils.isEmpty(executionOrders)) {
            return new ArrayList<>(0);
        }
        List<Long> excutionOrderIds = executionOrders.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
        List<ExcuteFeedback> excuteFeedbackList = CommonUtil.defaultList(excuteFeedbackMapper.selectList(Wrappers.lambdaQuery(ExcuteFeedback.class)
                .in(ExcuteFeedback::getExcutionOrderId, excutionOrderIds).eq(ExcuteFeedback::getIsDelete, NumberCst.ZERO)));
        Map<Long, Date> realPublishDateMap = new HashMap<>(excutionOrderIds.size());
        if (CollectionUtils.isNotEmpty(excuteFeedbackList)) {
            excuteFeedbackList.forEach(e -> {
                realPublishDateMap.putIfAbsent(e.getExcutionOrderId(), e.getRealPublishDate());
            });
        }
        //查询红人信息
        List<BasicExcutionOrderVO> excutionOrdersVO = this.basicExcutionOrderList(executionOrders);
        List<StarRebateExcutionOrderVO> dataList = new ArrayList<>(excutionOrdersVO.size());
        excutionOrdersVO.forEach(e -> {
            StarRebateExcutionOrderVO data = new StarRebateExcutionOrderVO();
            data.setId(e.getId());
            data.setExcuteCode(e.getExcuteCode());
            data.setIncomeContractCode(e.getIncomeContractCode());
            data.setBrandName(e.getBrandName());
            data.setProductName(e.getProductName());
            data.setStarNickName(e.getStarNickName());
            data.setPublishType(e.getPublishTypeName());
            data.setPlatformName(e.getPlatformName());
            data.setRealPublishDate(realPublishDateMap.get(e.getId()));
            dataList.add(data);
        });
        return dataList;
    }

    @Override
    public String getPurchaseContractCode(Integer state, String contractCode) {
        if (state == 1) {
            return purchaseContractMapper.getPurchaseContractCode(contractCode);
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String kocBatchImport(MultipartFile file) {
        String key = (String) stringRedisTemplate.opsForValue().get(REDIS_KEY_KOC_IMPORT + UserVoContextHolder.getUserVo().getTenantId());
        if (StringUtils.isNotBlank(key) || file.getSize() > REDIS_KEY_KOC_IMPORT_BATCH_IMPORT_SIZE) {
            throw new BusinessException(McnErrorCode.IMPORT_SIZE_ERROR);
        }

        boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(REDIS_KEY_KOC_IMPORT + UserVoContextHolder.getUserVo().getTenantId()
                , UserVoContextHolder.getUserVo().getRealName(), Duration.ofSeconds(60));
        if (!lock) {
            throw new BusinessException(McnErrorCode.IMPORT_SIZE_ERROR);
        }
        try {
            List<KocBatchImportExecutionDto> list = ExcelUtils.importExcel(file, KocBatchImportExecutionDto.class);
            list = list.stream().map(kocBatchImportExecutionDto -> {
                if (StringUtils.isNotBlank(kocBatchImportExecutionDto.getAccountName())) {
                    kocBatchImportExecutionDto.setAccountName(kocBatchImportExecutionDto.getAccountName().trim());
                }
                if (StringUtils.isNotBlank(kocBatchImportExecutionDto.getExcuteCode())) {
                    kocBatchImportExecutionDto.setExcuteCode(kocBatchImportExecutionDto.getExcuteCode().trim());
                }
                if (StringUtils.isNotBlank(kocBatchImportExecutionDto.getPublishUrl())) {
                    kocBatchImportExecutionDto.setPublishUrl(kocBatchImportExecutionDto.getPublishUrl().trim());
                }
                if (StringUtils.isNotBlank(kocBatchImportExecutionDto.getSettlementMethodName())) {
                    kocBatchImportExecutionDto.setSettlementMethodName(kocBatchImportExecutionDto.getSettlementMethodName().trim());
                }
                if (StringUtils.isNotBlank(kocBatchImportExecutionDto.getSettlementFormName())) {
                    kocBatchImportExecutionDto.setSettlementFormName(kocBatchImportExecutionDto.getSettlementFormName().trim());
                }
                return kocBatchImportExecutionDto;
            }).filter(t -> StringUtils.isNotBlank(t.getExcuteCode())).collect(Collectors.toList());
            List<String> excuteCodes = list.stream().map(KocBatchImportExecutionDto::getExcuteCode).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(excuteCodes)) {
                throw new BusinessException(McnErrorCode.IMPORT_TEMPLATE_WRONG);
            }
            if (excuteCodes.size() > McnConstant.MAX_IMPORT_SIZE) {
                throw new BusinessException(McnErrorCode.IMPORT_NUM_ERROR);
            }

            List<ContractExcutionOrder> contractExcutionOrders = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .in(ContractExcutionOrder::getExcuteCode, excuteCodes).ne(ContractExcutionOrder::getApprovalStatus, ApprovalStatusEnum.INVALID.getCode())
                    .eq(ContractExcutionOrder::getIsDelete, 0));
            //批量导入校验
            if (vertifyBatchImport(contractExcutionOrders, list)) {
                saveBatchImport(list);
            } else {
                return McnErrorCode.EXPORT_EXCEPTION.message();
            }
        } finally {
            stringRedisTemplate.delete(REDIS_KEY_KOC_IMPORT + UserVoContextHolder.getUserVo().getTenantId());
        }
        return null;
    }

    @Override
    public void kocBatchOutput(HttpServletResponse response) {
        String json = (String) stringRedisTemplate.opsForValue().get(BUSINESS_BATCH + UserVoContextHolder.getUserVo().getUserId());
        if (StringUtils.isEmpty(json)) {
            throw new BusinessException(McnErrorCode.IMPORT_ERROR_TIME_OUT);
        }
        List<KocBatchImportExecutionDto> kocBatchImportExecutionDtos = JSONObject.parseArray(json, KocBatchImportExecutionDto.class);

        ExcelUtils.exportExcel(kocBatchImportExecutionDtos, "收入合同执行单", KocBatchImportExecutionDto.class, "收入合同执行单.xlsx", response);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean forcedReject(Long id) {
        //执行单
        ContractExcutionOrder excutionOrder = contractExcutionOrderMapper.selectOne(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getId, id).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
        BusinessAssert.notNull(excutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        BusinessAssert.isTrue(ExcutionApprovalStatusEnum.anyMatch(excutionOrder.getApprovalStatus(),
                ExcutionApprovalStatusEnum.PASSED, ExcutionApprovalStatusEnum.PAID), McnErrorCode.BUSINESS_ERROR, "审批通过的执行单才允许强制驳回！");
        if (Objects.nonNull(excutionOrder.getStarRebateId())) {
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), "执行单已关联红人返点合同，不允许强制驳回");
        }
        //收入合同
        IncomeContract incomeContract = incomeContractMapper.selectOne(Wrappers.lambdaQuery(IncomeContract.class)
                .eq(IncomeContract::getId, excutionOrder.getIncomeContractId()).eq(IncomeContract::getIsDelete, NumberCst.ZERO));
        BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
        /**
         * 判断该单据是否能在财务模块费用表查询到非删除状态的费用
         */
        Integer relatedCount = financeClient.getInvalid(excutionOrder.getExcuteCode(), excutionOrder.getIncomeContractCode(), null).getObj();
        BusinessAssert.isFalse(relatedCount > 0, McnErrorCode.INVALID_FAILED,"请先作废该执行单生成的相应费用（来源单号）");
        relatedCount = financeClient.getInvalid(excutionOrder.getIncomeContractCode(), excutionOrder.getExcuteCode(), FinanceChargeTypeEnum.NO_STAR_INCOME.getType()).getObj();
        BusinessAssert.isFalse(relatedCount > 0, McnErrorCode.INVALID_FAILED, "请先作废收入合同生成的"+FinanceChargeTypeEnum.NO_STAR_INCOME.getDesc());
        StarMonthlySettlement starMonthlySettlement = settlementService.getSettlementByExcuteId(id);
        if (Objects.nonNull(starMonthlySettlement)) {
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), "执行单已关联红人月度结算单，不允许强制驳回");
        }
        //计算分成
        CalculationDevided calculationDevided = calculationDevidedMapper.getByExecuteId(id);
        BusinessAssert.notNull(calculationDevided, McnErrorCode.NO_CALCULATION_DEVIDED);
        LambdaUpdateWrapper<ContractExcutionOrder> lambdaUpdateWrapper = Wrappers.lambdaUpdate(ContractExcutionOrder.class);
        Date now = new Date();
        //是否需要回滚打款状态
        if(this.changePaybackIfNecessary(incomeContract, excutionOrder, calculationDevided)) {
            lambdaUpdateWrapper.set(ContractExcutionOrder::getPaybackStatus, NumberCst.ZERO)
                    .set(ContractExcutionOrder::getPaybackAmount, BigDecimal.ZERO)
                    .set(ContractExcutionOrder::getPaybackDate, null);
            this.updateContractPayback(incomeContract.getId(), excutionOrder, false);
        }
        //更新执行单
        contractExcutionOrderMapper.updateByNoStrategy(lambdaUpdateWrapper
                .set(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.EXECUTED.getCode())
                .set(ContractExcutionOrder::getPaidWay, null)
                .set(ContractExcutionOrder::getAccountId, null)
                .set(ContractExcutionOrder::getAccountType, null)
                .set(ContractExcutionOrder::getHandlingFeeRate, null)
                .set(ContractExcutionOrder::getCustomerInvoiceWay, null)
                .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                .set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                .set(ContractExcutionOrder::getUpdateDate, now)
                .eq(ContractExcutionOrder::getId, id));
        //更新计算分成
        calculationDevidedMapper.updateByNoStrategy(Wrappers.lambdaUpdate(CalculationDevided.class)
                .eq(CalculationDevided::getExcutionOrderId, id)
                .eq(CalculationDevided::getIsDelete, NumberCst.ZERO)
                .set(CalculationDevided::getFinanceDevidedAmount, null)
                .set(CalculationDevided::getAmountReceivable, null)
                .set(CalculationDevided::getFinanceCulturalTax, null)
                .set(CalculationDevided::getFinanceDevidedRemark, null)
                .set(CalculationDevided::getUpdateBy, UserVoContextHolder.getUserId())
                .set(CalculationDevided::getUpdateName, UserVoContextHolder.getUserName())
                .set(CalculationDevided::getUpdateDate, now));

        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(id)
                .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                .compare(calculationDevided, calculationDevidedMapper.getByExecuteId(id)).build());

        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(id)
                .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                .compare(excutionOrder, contractExcutionOrderMapper.selectById(id)).build());
        return Boolean.TRUE;
    }

    @Override
    public BatchConfirmPaidResultVO batchConfirmPaid(BatchConfirmPaidDTO dto) {
        List<ContractExcutionOrder> excutionOrderList = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .in(ContractExcutionOrder::getId, dto.getIdList()).eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE));
        BusinessAssert.notEmpty(excutionOrderList, McnErrorCode.EXECUTION_NOT_EXISTS);
        List<Long> excuteIdList = excutionOrderList.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
        List<CalculationDevided> calculationDevidedList = CommonUtil.defaultList(calculationDevidedMapper.selectList(Wrappers.lambdaQuery(CalculationDevided.class)
                .in(CalculationDevided::getExcutionOrderId, excuteIdList).eq(CalculationDevided::getIsDelete, Boolean.FALSE)));
        Map<Long, CalculationDevided> calculationDevidedMap = calculationDevidedList.stream().collect(Collectors.toMap(k -> k.getExcutionOrderId(), v -> v, (o, n) -> o));
        BatchConfirmPaidResultVO resultVO = new BatchConfirmPaidResultVO();
        excutionOrderList.forEach(excutionOrder -> {
            //请加锁
            StringBuilder failedReason = new StringBuilder();
            if (!ExcutionApprovalStatusEnum.isPassed(excutionOrder.getApprovalStatus())) {
                failedReason.append("单据状态须是待打款！");
            }
            CalculationDevided calculationDevided = calculationDevidedMap.get(excutionOrder.getId());
            if (Objects.isNull(calculationDevided)) {
                failedReason.append("查询不到计算分成信息！");
            } else {
                /*if (!SettlementMethodEnum.BATCH_REMITTANCE.getCode().equals(calculationDevided.getSettlementMethod())) {
                    failedReason.append("结算方式须是批量打款！");
                }*/
                if (!NumberCst.ONE.equals(calculationDevided.getSettlementForm())) {
                    failedReason.append("结算形式须是线下结算！");
                }
            }
            if (failedReason.length() > 0) {
                resultVO.addFailResult(excutionOrder.getExcuteCode(), failedReason.toString());
            } else {
                try {
                    ContractExcutionOrder updateExcutionOrder = new ContractExcutionOrder();
                    updateExcutionOrder.setId(excutionOrder.getId());
                    updateExcutionOrder.setApprovalStatus(ExcutionApprovalStatusEnum.PAID.getCode());
                    updateExcutionOrder.setPaidStarDate(dto.getPaidDate());
                    updateExcutionOrder.setPaidRemark(StringUtils.defaultString(dto.getPaidRemark()));
                    boolean result = contractExcutionOrderMapper.updateById(updateExcutionOrder) > 0;
                    if (result) {
                        //操作日志
                        EventPublisher.post(OperateLogEvent.builder().businessId(excutionOrder.getId())
                                .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                                .compare(excutionOrder, contractExcutionOrderMapper.selectById(excutionOrder.getId()))
                                .build());
                    }
                    resultVO.setSuccessNum(resultVO.getSuccessNum().intValue() + 1);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    resultVO.addFailResult(excutionOrder.getExcuteCode(), "状态更新异常");
                }
            }
        });
        return resultVO;
    }

    @Override
    public List<FinanceExcutionOrderVO> getFinanceExcutionOrderByCodes(List<String> excuteCodes) {
        List<FinanceExcutionOrderVO> dataList = contractExcutionOrderMapper.getFinanceExcutionOrderByCodes(excuteCodes);
         if (CollectionUtils.isNotEmpty(dataList)) {
             //查询品牌
             List<String> brandCodes = dataList.stream().map(FinanceExcutionOrderVO::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
             Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
             dataList.forEach(e -> {
                 if(brandMap.containsKey(e.getBrandName())) {
                     e.setCooperateBrandName(brandMap.get(e.getBrandName()));
                 }
             });
         }
        return dataList;
    }


    private void saveBatchImport(List<KocBatchImportExecutionDto> list) {
        for (KocBatchImportExecutionDto executionDto : list) {
            calculationDevidedMapper.update(null, Wrappers.lambdaUpdate(CalculationDevided.class)
                    .eq(CalculationDevided::getExcutionOrderId, executionDto.getId())
                    .set(CalculationDevided::getSettlementMethod, executionDto.getSettlementMethod())
                    .set(CalculationDevided::getSettlementForm, executionDto.getSettlementForm())
                    .set(CalculationDevided::getHandPrice, executionDto.getHandPrice()));
            ContractExcutionOrder contractExcutionOrder = new ContractExcutionOrder();
            contractExcutionOrder.setId(executionDto.getId());
            contractExcutionOrder.setOtherFee(executionDto.getOtherFee());
            contractExcutionOrder.setStarAccountInfoId(executionDto.getStarAccountInfoId());
            contractExcutionOrderMapper.updateById(contractExcutionOrder);
            excuteFeedbackMapper.update(null, Wrappers.lambdaUpdate(ExcuteFeedback.class)
                    .eq(ExcuteFeedback::getExcutionOrderId, executionDto.getId())
                    .set(ExcuteFeedback::getPublishUrl, executionDto.getPublishUrl()));
            //2022/6/1 14:28 注释掉审批流
            ExcutionOrderDetailVO excutionOrderDetailVO = detail(executionDto.getId());
            ExcutionOrderUpdateDTO excutionOrderUpdateDTO = new ExcutionOrderUpdateDTO();
            BeanUtils.copyProperties(excutionOrderDetailVO, excutionOrderUpdateDTO);
            excutionOrderUpdateDTO.setExcuteFeedback(excutionOrderDetailVO.getExcuteFeedback());
            excutionOrderUpdateDTO.setCalculationDevided(excutionOrderDetailVO.getCalculationDevided());
            excutionOrderUpdateDTO.setApprovalStatus(ExcutionApprovalStatusEnum.EXECUTING.getCode());
            update(excutionOrderUpdateDTO, false);
        }
    }

    private boolean vertifyBatchImport(List<ContractExcutionOrder> contractExcutionOrders, List<KocBatchImportExecutionDto> origin) {
        Map<String, ContractExcutionOrder> excuteCodeMap = contractExcutionOrders.stream().collect(Collectors.toMap(ContractExcutionOrder::getExcuteCode, Function.identity()));
        List<Long> starIds = contractExcutionOrders.stream().map(ContractExcutionOrder::getStarId).filter(t -> Objects.nonNull(t)).collect(Collectors.toList());
        List<StarAccountInfo> starAccountInfos;
        if (CollectionUtil.isNotEmpty(starIds)) {
            starAccountInfos = starAccountInfoMapper.selectList(Wrappers.lambdaQuery(StarAccountInfo.class)
                    .in(StarAccountInfo::getStarId, starIds).eq(StarAccountInfo::getIsDelete, 0));
        } else {
            starAccountInfos = new ArrayList<>();
        }
        List<Long> incomeContractIds = contractExcutionOrders.stream().map(ContractExcutionOrder::getIncomeContractId).distinct().collect(Collectors.toList());
        List<IncomeContract> incomeContracts = incomeContractMapper.selectBatchIds(incomeContractIds);
        List<ContractExcutionOrder> allExcutionOrders = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .in(ContractExcutionOrder::getIncomeContractId, incomeContractIds)
                .ne(ContractExcutionOrder::getApprovalStatus, ApprovalStatusEnum.INVALID.getCode())
                .eq(ContractExcutionOrder::getIsDelete, 0));

        List<Long> agreementIds = contractExcutionOrders.stream().map(ContractExcutionOrder::getContractAgreementId).distinct().collect(Collectors.toList());
        List<IncomeContractAgreement> incomeContractAgreements;
        if (CollectionUtil.isNotEmpty(agreementIds)) {
            incomeContractAgreements = incomeContactAgreementMapper.selectList(Wrappers.lambdaQuery(IncomeContractAgreement.class)
                    .in(IncomeContractAgreement::getId, agreementIds)
                    .eq(IncomeContractAgreement::getIsDelete, Boolean.FALSE)
                    .eq(IncomeContractAgreement::getApprovalStatus, ApprovalStatusEnum.PASSED.code()));
        } else {
            incomeContractAgreements = new ArrayList<>();
        }

        Map<Long, List<ContractExcutionOrder>> allExcutionMap = allExcutionOrders.stream().collect(Collectors.groupingBy(ContractExcutionOrder::getIncomeContractId));

        starAccountInfos.sort(Comparator.comparing(StarAccountInfo::getCreateDate));
        List<KocBatchImportExecutionDto> kocBatchoutErrors = new ArrayList<>();
        Set<String> excuteCodeSets = new HashSet<>();
        origin.forEach(kocBatchImportExecutionDto -> {
            StringBuilder stringBuilder = new StringBuilder();
            ContractExcutionOrder excutionOrder = excuteCodeMap.get(kocBatchImportExecutionDto.getExcuteCode());
            if (!excuteCodeSets.add(kocBatchImportExecutionDto.getExcuteCode())) {
                stringBuilder.append("执行单编号重复;");
            } else {
                if (excutionOrder == null) {
                    stringBuilder.append("请书输入正确的执行单编号;");
                } else {
                    //校验有效执行单
                    vertifyActiveExcutionOrder(starAccountInfos, incomeContracts, allExcutionMap, kocBatchImportExecutionDto, stringBuilder, excutionOrder,
                            incomeContractAgreements);
                }
            }
            if (StringUtils.isNotBlank(stringBuilder.toString())) {
                kocBatchImportExecutionDto.setError(stringBuilder.toString());
                kocBatchoutErrors.add(kocBatchImportExecutionDto);
            }
        });
        if (kocBatchoutErrors.size() > 0) {
            stringRedisTemplate.opsForValue().set(BUSINESS_BATCH + UserVoContextHolder.getUserVo().getUserId(),
                    JSONObject.toJSONString(origin), Duration.ofHours(48));
        }

        return kocBatchoutErrors.size() == 0;
    }

    private void vertifyActiveExcutionOrder(List<StarAccountInfo> starAccountInfos, List<IncomeContract> incomeContracts, Map<Long, List<ContractExcutionOrder>> allExcutionMap,
                                            KocBatchImportExecutionDto kocBatchImportExecutionDto, StringBuilder stringBuilder, ContractExcutionOrder excutionOrder,
                                            List<IncomeContractAgreement> incomeContractAgreements) {
        kocBatchImportExecutionDto.setId(excutionOrder.getId());
        if (!excutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.UN_EXECUTE.getCode()) &&
                !excutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.EXECUTING.getCode()) &&
                !excutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.EXECUTED.getCode())) {
            stringBuilder.append("执行单状态须是待执行、执行中或者已执行;");
        }

        if (!excutionOrder.getType().equals(ExcutionOrderTypeEnum.KOC_EXCUTION_ORDER.getType())) {
            stringBuilder.append("执行单类型须是【KOC红人执行单】;");
        }

        if (excutionOrder.getContractAgreementId() != null) {
            if (!incomeContractAgreements.stream().filter(t -> t.getId().equals(excutionOrder.getContractAgreementId())).findFirst().isPresent()) {
                stringBuilder.append("补充协议需要审批通过;");
            }
        }

        if (kocBatchImportExecutionDto.getHandPrice() == null ||
                kocBatchImportExecutionDto.getHandPrice().scale() > NumberCst.TWO || kocBatchImportExecutionDto.getHandPrice().compareTo(BigDecimal.ZERO) < 0) {
            stringBuilder.append("【本单固定到手价】仅能输入大于等于0，最多含2位小数的数字;");
        }

        if (kocBatchImportExecutionDto.getOtherFee() == null || kocBatchImportExecutionDto.getOtherFee().scale() > NumberCst.TWO || kocBatchImportExecutionDto.getOtherFee().compareTo(BigDecimal.ZERO) < 0) {
            stringBuilder.append("【其他费用】仅能输入大于等于0，最多含2位小数的数字;");
        }

        if (kocBatchImportExecutionDto.getPublishUrl() == null || kocBatchImportExecutionDto.getPublishUrl().length() > 1000) {
            stringBuilder.append("【发布链接】不能为空且长度不能超过1000个字符长度;");
        }

        if (StringUtils.isNotBlank(kocBatchImportExecutionDto.getAccountName())) {
            List<StarAccountInfo> starAccountInfos2 = starAccountInfos.stream().filter(t -> t.getAccountName().equals(kocBatchImportExecutionDto.getAccountName())).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(starAccountInfos2)) {
                stringBuilder.append("【收款户名】基础档案中找不到收款户名，请在红人档案中录入;");
            } else {
                kocBatchImportExecutionDto.setStarAccountInfoId(starAccountInfos2.get(starAccountInfos.size() - 1).getId());
            }
        } else {
            if (starAccountInfos.size() == 0) {
                stringBuilder.append("请补充红人收款账户数据;");
            } else {
                kocBatchImportExecutionDto.setStarAccountInfoId(starAccountInfos.get(starAccountInfos.size() - 1).getId());
            }
        }
        if (!SettlementMethodEnum.BATCH_REMITTANCE.getName().equals(kocBatchImportExecutionDto.getSettlementMethodName())) {
            stringBuilder.append("【结算方式】仅能录入【批量打款】;");
        } else {
            kocBatchImportExecutionDto.setSettlementMethod(SettlementMethodEnum.BATCH_REMITTANCE.getCode());
        }
        if (McnConstant.ONLING_SETTLEMENT.equals(kocBatchImportExecutionDto.getSettlementFormName())) {
            kocBatchImportExecutionDto.setSettlementForm(0);
        } else if (McnConstant.OFFLING_SETTLEMENT.equals(kocBatchImportExecutionDto.getSettlementFormName())) {
            kocBatchImportExecutionDto.setSettlementForm(1);
        } else {
            stringBuilder.append("仅能录入【线上结算】或者【线下结算】;");
        }

        //校验金额
        vertifyMoney(incomeContracts, allExcutionMap, kocBatchImportExecutionDto, stringBuilder, excutionOrder);
    }

    private void vertifyMoney(List<IncomeContract> incomeContracts, Map<Long, List<ContractExcutionOrder>> allExcutionMap, KocBatchImportExecutionDto kocBatchImportExecutionDto, StringBuilder stringBuilder, ContractExcutionOrder excutionOrder) {
        IncomeContract incomeContract = incomeContracts.stream().filter(t -> t.getId().equals(excutionOrder.getIncomeContractId())).findFirst().get();
        if (!IncomeContractTypeEnum.LIVE_CONTRACT.getType().equals(incomeContract.getContractType())) {
            //其他费用+本单固定到手价=执行单总金额
            if (kocBatchImportExecutionDto.getHandPrice() != null && kocBatchImportExecutionDto.getOtherFee() != null) {
                if (kocBatchImportExecutionDto.getHandPrice().add(kocBatchImportExecutionDto.getOtherFee())
                        .compareTo(excutionOrder.getActualQuotedPrice()) != 0) {
                    stringBuilder.append("【其他费用】加上【本单固定到手价】需要等于【执行单总金额】;");
                } else {
                    //校验收入合同下所有非作废状态的执行单总金额之和等于商务确认合同金额。
                    List<ContractExcutionOrder> excutionOrders = allExcutionMap.get(excutionOrder.getIncomeContractId());
                    ContractExcutionOrder contractExcutionOrder = excutionOrders.stream().filter(t -> t.getId().equals(excutionOrder.getId())).findFirst().get();
                    contractExcutionOrder.setActualQuotedPrice(excutionOrder.getActualQuotedPrice());

                    if (!ApprovalStatusEnum.isPassed(incomeContract.getApprovalStatus())) {
                        stringBuilder.append("收入合同未审批通过，不能提交执行单;");
                    }

                    BigDecimal excutionSum = excutionOrders.stream().map(ContractExcutionOrder::getActualQuotedPrice).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
                    if (incomeContract.getBusinessAmount().compareTo(excutionSum) != 0) {
                        stringBuilder.append("收入合同下所有非作废状态的【执行单总金额】之和需要等于【商务确认合同金额】;");
                    }
                }
            }
        }
    }

    @Deprecated
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changePaidCallback(ExcutionOrderChangePaidCallback changePaidCallback) {
        String messageBody = JSONObject.toJSONString(changePaidCallback);
        MessageInfo messageInfo = MessageInfo.builder()
                .messageTopic(MessageTopicEnum.CHANGE_PAID_CALLBACK_ZXD.name())
                .messageKey(CommonUtil.getMessageKey(null))
                .messageBody(messageBody)
                .signature(CommonUtil.hmacMd5Hex(messageBody))
                .status(MessageStatusEnum.SUCCESS.getType())
                .tenantId(Optional.ofNullable(changePaidCallback.getTenantId()).orElse(UserVoContextHolder.getTenantId()))
                .build();
        messageInfoService.addMessageInfo(messageInfo);
        ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectOne(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getExcuteCode, changePaidCallback.getExcuteCode())
                .eq(ContractExcutionOrder::getTenantId, UserVoContextHolder.getTenantId()));
        BusinessAssert.notNull(contractExcutionOrder, McnErrorCode.DATA_NOT_FOUND, "查询不到该执行单信息");
        boolean result = contractExcutionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(ContractExcutionOrder.class)
                .set(ContractExcutionOrder::getPaidWay, changePaidCallback.getPaidWay())
                .set(ContractExcutionOrder::getCustomerInvoiceWay, changePaidCallback.getCustomerInvoiceWay())
                .set(ContractExcutionOrder::getUpdateBy, changePaidCallback.getOperatorId())
                .set(ContractExcutionOrder::getUpdateName, changePaidCallback.getOperatorName())
                .set(ContractExcutionOrder::getUpdateDate, new Date())
                .eq(ContractExcutionOrder::getId, contractExcutionOrder.getId()));
        if (result) {
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(contractExcutionOrder.getId())
                    .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                    .compare(contractExcutionOrder, contractExcutionOrderMapper.selectById(contractExcutionOrder.getId()))
                    .build());
        }
        return result;
    }

    @Override
    public ContractExcutionOrder getByCode(String excuteCode) {
        return contractExcutionOrderMapper.selectOne(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getExcuteCode, excuteCode)
                .eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE));
    }

    /**
     * 设置创建人部门名称
     */
    private String getDepartment(Long userId) {
        List<SUserVo> userList = privilegeClient.getDepartmentByUserIds(Collections.singletonList(userId)).getObj();
        if (CollectionUtil.isNotEmpty(userList)) {
            Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(SUserVo::getUserId, SUserVo::getDepartmentName));
            return userMap.get(userId);
        }
        return null;
    }


    /**
     * 判断审批状态
     *
     * @param contractExcutionOrder {@link ContractExcutionOrder}
     * @param status                {@link Integer}
     */
    private void validateStatus(ContractExcutionOrder contractExcutionOrder, Integer status) {
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.UN_EXECUTE.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.EXECUTING, ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_UN_EXECUTE_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.EXECUTING.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.EXECUTED ,ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_EXECUTING_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.EXECUTED.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.CONFIRMING, ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_EXECUTED_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.CONFIRMING.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.APPROVAL, ExcutionApprovalStatusEnum.EXECUTED, ExcutionApprovalStatusEnum.CONFIRM_REJECTED, ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_CONFIRMING_ERROR);
        }
//        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.CONFIRMED.code()) &&
//                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.APPROVAL, ExcutionApprovalStatusEnum.INVALID)) {
//            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_CONFIRMED_ERROR);
//        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.CONFIRM_REJECTED.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.CONFIRMING, ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_CONFIRM_REJECTED_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.APPROVAL.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.CANCEL, ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_UN_COMMIT_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.PASSED.code()) &&
                !status.equals(ExcutionApprovalStatusEnum.INVALID.code())) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_PASSED_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.PAID.code()) &&
                !status.equals(ExcutionApprovalStatusEnum.INVALID.code())) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_PAID_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.REJECTED.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.APPROVAL, ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_REJECTED_ERROR);
        }
        if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.CANCEL.code()) &&
                !ExcutionApprovalStatusEnum.anyMatch(status, ExcutionApprovalStatusEnum.APPROVAL, ExcutionApprovalStatusEnum.INVALID)) {
            throw new BusinessException(McnErrorCode.CONTRACT_EXCUTION_ORDER_CANCEL_ERROR);
        }

        if (ExcutionApprovalStatusEnum.isInvalid(contractExcutionOrder.getApprovalStatus())) {
            throw new BusinessException(McnErrorCode.EXECUTION_INVALID);
        }
        if (ExcutionApprovalStatusEnum.isPassed(status)) {
            if (contractExcutionOrder.getApprovalStatus().equals(ExcutionApprovalStatusEnum.CANCEL.code())) {
                throw new BusinessException(McnErrorCode.EXECUTION_CANCELED);
            }
        }
        if (ExcutionApprovalStatusEnum.APPROVAL.code().equals(status)) {
            if (ExcutionOrderTypeEnum.isOutside(contractExcutionOrder.getType())) {
                verifyPurchase(contractExcutionOrder);
            }
        }
    }

    @Override
    public BigDecimal getSysDevidedAmount(ContractExcutionOrder contractExcutionOrder, CalculationDevided calculationDevided) {
        if(Objects.isNull(calculationDevided)) {
            calculationDevided = calculationDevidedMapper.getByExecuteId(contractExcutionOrder.getId());
            BusinessAssert.notNull(calculationDevided, McnErrorCode.NO_CALCULATION_DEVIDED);
        }

        //原逻辑：统计算分成金额=（内容实际报价+其他加价收入）*（1-内容报价返点比例）*（1-平台服务费比例）*红人分成比例 / 1.06
//        BigDecimal aeCustomerRabateRate = calculationDevided.getAeCustomerRabateRate();
//        BigDecimal t1 = ObjectUtils.defaultIfNull(contractExcutionOrder.getRealAmount(), BigDecimal.ZERO)
//                .add(ObjectUtils.defaultIfNull(contractExcutionOrder.getOtherAmount(), BigDecimal.ZERO));
//        BigDecimal t2 = BigDecimal.ONE.subtract(ObjectUtils.defaultIfNull(aeCustomerRabateRate, BigDecimal.ZERO).divide(BigDecimal.valueOf(100)));
        OrderPlatformInfo orderPlatformInfo = orderPlatformInfoMapper.selectOne(Wrappers.lambdaQuery(OrderPlatformInfo.class)
                .eq(OrderPlatformInfo::getOrderPlatform, contractExcutionOrder.getOrderPlatform()).eq(OrderPlatformInfo::getIsDelete, NumberCst.ZERO));
        BigDecimal serivceFeeRate = BigDecimal.ZERO;
        if(Objects.nonNull(orderPlatformInfo)) {
            serivceFeeRate = ObjectUtils.defaultIfNull(orderPlatformInfo.getSerivceFeeRate(), BigDecimal.ZERO);
        }
//        BigDecimal sysDevidedAmount = t1.multiply(t2).multiply(BigDecimal.ONE.subtract(serivceFeeRate))
//                .multiply(ObjectUtils.defaultIfNull(contractExcutionOrder.getDividedRate(), BigDecimal.ZERO)
//                .divide(BigDecimal.valueOf(100)))
//                .divide(new BigDecimal("1.06"), 2, BigDecimal.ROUND_HALF_UP);
        //新逻辑：（执行单总金额 / 1.06 - 内容报价返点金额 - （执行单总金额 * 平台服务费比例） - 平台手续费或者微任务金额 - 机酒差旅补贴 - 其他补贴性收入）* 红人分成比例
        BigDecimal t1 = ObjectUtils.defaultIfNull(contractExcutionOrder.getActualQuotedPrice(), BigDecimal.ZERO).divide(new BigDecimal("1.06"), 5, BigDecimal.ROUND_HALF_UP);
        BigDecimal t2 = ObjectUtils.defaultIfNull(contractExcutionOrder.getActualQuotedPrice(), BigDecimal.ZERO).multiply(serivceFeeRate);
        BigDecimal t3 = t1.subtract(ObjectUtils.defaultIfNull(calculationDevided.getAeCustomerRabateAmount(), BigDecimal.ZERO))
                .subtract(t2)
                .subtract(ObjectUtils.defaultIfNull(contractExcutionOrder.getPlatformFee(), BigDecimal.ZERO))
                .subtract(ObjectUtils.defaultIfNull(contractExcutionOrder.getOtherFee(), BigDecimal.ZERO))
                .subtract(ObjectUtils.defaultIfNull(contractExcutionOrder.getSubsidyIncomeAmount(), BigDecimal.ZERO));
        BigDecimal sysDevidedAmount = t3.multiply(ObjectUtils.defaultIfNull(contractExcutionOrder.getDividedRate(), BigDecimal.ZERO))
                .divide(McnConstant.ONE_HUNDRED, 2, BigDecimal.ROUND_HALF_UP);
        return sysDevidedAmount;
    }



    @Override
    public BigDecimal getYearRebateRate(ContractExcutionOrder contractExcutionOrder) {
        BigDecimal yearRebateRate = BigDecimal.ZERO;

        /**
         * 查询收入合同
         */
        IncomeContract incomeContract = incomeContractService.selectById(contractExcutionOrder.getIncomeContractId());
        if (Objects.isNull(incomeContract)) {
            return yearRebateRate;
        }
        IncomeContractTypeEnum contractTypeEnum = IncomeContractTypeEnum.getType(incomeContract.getContractType());
        /**
         * 无折扣审批单，返点为0
         */
        if (incomeContract.getDiscountId() == null) {
            return yearRebateRate;
        }
        /**
         * 查询折扣审批单
         */
        DiscountApproval discountApproval = discountApprovalMapper.selectById(incomeContract.getDiscountId());

        /**
         * 查询红人相关信息
         */
        StarPlatInfoVO starPlatInfoVO = starPlatformInfoService.getById(contractExcutionOrder.getStarPlatformInfoId());

        BigDecimal sysDevidedAmount = BigDecimal.ZERO;

        /**
         * 单笔优惠折扣审批单：单笔返点比例；
         */
        if (!discountApproval.getApprovalType().equals(DiscountApprovalEnum.SINGLE_DISCOUNT.code())) {
            /**
             * 年度优惠含平台返点的年度累计金额
             */
            BigDecimal withYearAmount = BigDecimal.ZERO;
            BigDecimal withYearAmountGet = discountApprovalService.getWithYearAmount(incomeContract.getCustomerId(), incomeContract.getDiscountId());
            if (withYearAmountGet != null) {
                withYearAmount = withYearAmountGet;
            }
            /**
             * 年度优惠不含平台返点的年度累计金额
             */
            BigDecimal withNoYearAmount = BigDecimal.ZERO;
            BigDecimal withNoYearAmountGet =
                    discountApprovalService.getWithNoYearAmount(
                            incomeContract.getCustomerId(), incomeContract.getDiscountId());
            if (withNoYearAmountGet != null) {
                withNoYearAmount = withNoYearAmountGet;
            }

            Integer discountType = discountApproval.getDiscountType();
            DiscountApprovalEnum discountTypeEnum = DiscountApprovalEnum.getByCode("discountType", discountType);
            switch (discountTypeEnum) {
                /**
                 * 年度优惠含平台返点
                 */
                case YEAR_WITH_PLATFORM_DISCOUNT:
                    if (starPlatInfoVO != null) {
                        BigDecimal matchedRate = platformDiscountRangeService.getMatchedRate(incomeContract.getDiscountId(), starPlatInfoVO.getPlatformId(), withYearAmount);
                        if (matchedRate != null) {
                            yearRebateRate = matchedRate;
                        }
                    }
                    break;

                /**
                 * 年度优惠不含平台返点
                 */
                case YEAR_NOT_WITH_PLATFORM_DISCOUNT:
                    BigDecimal incomeMatchedRate = platformDiscountRangeService.getMatchedRate(incomeContract.getDiscountId(), starPlatInfoVO.getPlatformId(), withNoYearAmount);
                    if (incomeMatchedRate != null) {
                        yearRebateRate = incomeMatchedRate;
                    }
                    break;
                /**
                 * 仅年度优惠
                 */
                case YEAR_TYPE_DISCOUNT:
                    BigDecimal yearMatchedRate = platformDiscountRangeService.getMatchedRate(incomeContract.getDiscountId(), starPlatInfoVO.getPlatformId(), withYearAmount);
                    if (yearMatchedRate != null) {
                        yearRebateRate = yearMatchedRate;
                    }
                    break;
                default:
                    ;
            }
        }
        return yearRebateRate;
    }

    /**
     * 保存执行反馈
     * @param excuteFeedback
     * @param contractExcutionOrder
     */
    private void saveExcuteFeedback(ExcuteFeedback excuteFeedback, ContractExcutionOrder contractExcutionOrder) {
        if (excuteFeedback.getId() == null) {
            excuteFeedback.setExcutionOrderId(contractExcutionOrder.getId());
            excuteFeedback.setExcutionOrderCode(contractExcutionOrder.getExcuteCode());
            excuteFeedbackMapper.insert(excuteFeedback);
        } else {
            ExcuteFeedback beforeFeedback = excuteFeedbackMapper.selectById(excuteFeedback.getId());
            excuteFeedbackMapper.updateByNoStrategy(Wrappers.<ExcuteFeedback>lambdaUpdate()
                    .set(ExcuteFeedback::getRealPublishDate, excuteFeedback.getRealPublishDate())
                    .set(ExcuteFeedback::getPublishUrl, excuteFeedback.getPublishUrl())
                    .set(ExcuteFeedback::getPublishImg, excuteFeedback.getPublishImg())
                    .set(ExcuteFeedback::getConversionAmount, excuteFeedback.getConversionAmount())
                    .set(ExcuteFeedback::getInteractQuantity, excuteFeedback.getInteractQuantity())
                    .set(ExcuteFeedback::getReadQuantity, excuteFeedback.getReadQuantity())
                    .set(ExcuteFeedback::getPlayQuantity, excuteFeedback.getPlayQuantity())
                    .set(ExcuteFeedback::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(ExcuteFeedback::getUpdateName, UserVoContextHolder.getUserName())
                    .set(ExcuteFeedback::getUpdateDate, new Date())
                    .eq(ExcuteFeedback::getId, excuteFeedback.getId())
            );
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(excuteFeedback.getExcutionOrderId())
                    .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                    .compare(beforeFeedback, excuteFeedback).build());
        }
    }


    public void saveCalculationDevided(CalculationDevided calculationDevided, ContractExcutionOrder afterContractExcutionOrder) {
        /**
         * 关联客户无红人结算固定返点比例则保存年度优惠返点比例
         */
        if (calculationDevided.getId() == null) {
            /**
             * 新增
             */
            IncomeContract incomeContract = incomeContractService.selectById(afterContractExcutionOrder.getIncomeContractId());
            Map<Long, BaseCustomer> customerMap = baseInfoClient.getMcnCustomerByIds(Arrays.asList(incomeContract.getCustomerId())).getObj();
            if (customerMap.get(incomeContract.getCustomerId()).getFixedRebateRatio() == null) {
                calculationDevided.setYearRebateRate(getYearRebateRate(afterContractExcutionOrder));
            }
            //calculationDevided.setCustomerRebateRate(this.getCustomerRebateRate(afterContractExcutionOrder));
            if (afterContractExcutionOrder.getActualQuotedPrice() != null && calculationDevided.getCustomerRebateRate() != null) {
                calculationDevided.setCustomerRebateAmount(afterContractExcutionOrder.getActualQuotedPrice()
                        .multiply(calculationDevided.getCustomerRebateRate().divide(BigDecimal.valueOf(100))));
            }
            calculationDevided.setExcutionOrderId(afterContractExcutionOrder.getId());
            calculationDevided.setExcutionOrderCode(afterContractExcutionOrder.getExcuteCode());
            calculationDevidedMapper.insert(calculationDevided);
        } else {
            boolean eq1 = SettlementMethodEnum.isRemittance(calculationDevided.getSettlementMethod()) &&
                    ObjectUtils.defaultIfNull(calculationDevided.getAeDevidedAmount(), BigDecimal.ZERO)
                    .compareTo(ObjectUtils.defaultIfNull(calculationDevided.getSysDevidedAmount(), BigDecimal.ZERO))  != 0;
            boolean eq2 = SettlementMethodEnum.isRemittance(calculationDevided.getSettlementMethod()) &&
                    ObjectUtils.defaultIfNull(calculationDevided.getAeCulturalTax(), BigDecimal.ZERO)
                    .compareTo(ObjectUtils.defaultIfNull(calculationDevided.getSysCulturalTax(), BigDecimal.ZERO))  != 0;
            if(eq1 && eq2) {
                BusinessAssert.notBlank(calculationDevided.getRemark(), McnErrorCode.BUSINESS_ERROR, "AE确认分成金额≠系统计算分成金额，AE确认文建税≠系统计算文建税，请在“AE备注”中进行差异说明！");
            } else if(eq1) {
                BusinessAssert.notBlank(calculationDevided.getRemark(), McnErrorCode.BUSINESS_ERROR, "AE确认分成金额≠系统计算分成金额，请在“AE备注”中进行差异说明！");
            } else if(eq2) {
                BusinessAssert.notBlank(calculationDevided.getRemark(), McnErrorCode.BUSINESS_ERROR, "AE确认文建税≠系统计算文建税，请在“AE备注”中进行差异说明！");
            }
            CalculationDevided beforeCalculationDevided = calculationDevidedMapper.selectById(calculationDevided.getId());
            calculationDevidedMapper.updateDetail(calculationDevided);
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(calculationDevided.getExcutionOrderId())
                    .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                    .compare(beforeCalculationDevided, calculationDevided)
                    .build());
        }
    }

    @Override
    public List<ContractExcutionOrder> getByAgreement(List<Long> agreementIds) {
        List<ContractExcutionOrder> excutionOrders = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .in(ContractExcutionOrder::getContractAgreementId, agreementIds).eq(ContractExcutionOrder::getIsDelete, false));
        if (CollectionUtil.isNotEmpty(excutionOrders)) {
            List<Long> excutionIds = excutionOrders.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
            List<CalculationDevided> calculationDevideds = calculationDevidedMapper.selectList(Wrappers.lambdaQuery(CalculationDevided.class).in(CalculationDevided::getExcutionOrderId, excutionIds));
            Map<Long, CalculationDevided> calculationDevidedMap = calculationDevideds.stream().collect(Collectors.toMap(CalculationDevided::getExcutionOrderId, x -> x, (x, y) -> x));
            //查询意向单
            Map<String, DocIntentionOrder> intentionOrderMap = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(excutionIds), () ->
                            CommonUtil.defaultList(intentionOrderMapper.selectList(Wrappers.lambdaQuery(DocIntentionOrder.class).in(DocIntentionOrder::getExcutionOrderId, excutionIds)))
                                    .stream().collect(Collectors.toMap(DocIntentionOrder::getExcutionOrderCode, x -> x, (x, y) -> x))
                    , Collections.EMPTY_MAP);
            excutionOrders.forEach(e ->{
                CalculationDevided calculationDevided =calculationDevidedMap.get(e.getId());
                if (Objects.nonNull(calculationDevided)) {
                    e.setAeCustomerRabateRate(calculationDevided.getAeCustomerRabateRate());
                    e.setAeCustomerRabateAmount(calculationDevided.getAeCustomerRabateAmount());
                    e.setActualDiscountRatio(calculationDevided.getActualDiscountRatio());
                    e.setCustomerRebateRate(calculationDevided.getCustomerRebateRate());
                }
                DocIntentionOrder intentionOrder = intentionOrderMap.get(e.getExcuteCode());
                if(Objects.nonNull(intentionOrder)) {
                    e.setIntentionOrderId(intentionOrder.getId());
                }
            });


        }
        return excutionOrders;
    }


    /**
     * 查询合同下执行单
     *
     * @param incomeContractId
     * @return List<ContractExcutionOrder>
     */
    @Override
    public List<ContractExcutionOrder> getByContractId(Long incomeContractId) {
        QueryWrapper<ContractExcutionOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(ContractExcutionOrder::getIncomeContractId, incomeContractId)
                .eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE);
        List<ContractExcutionOrder> excutionOrders = contractExcutionOrderMapper.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(excutionOrders)) {
            List<Long> excutionIds = excutionOrders.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
            List<CalculationDevided> calculationDevideds = calculationDevidedMapper.selectList(Wrappers.lambdaQuery(CalculationDevided.class).in(CalculationDevided::getExcutionOrderId, excutionIds));
            Map<Long, CalculationDevided> calculationDevidedMap = calculationDevideds.stream().collect(Collectors.toMap(CalculationDevided::getExcutionOrderId, x -> x, (x, y) -> x));
            excutionOrders.forEach(e -> {
                CalculationDevided calculationDevided = calculationDevidedMap.get(e.getId());
                if (Objects.nonNull(calculationDevided)) {
                    e.setAeCustomerRabateRate(calculationDevided.getAeCustomerRabateRate());
                    e.setAeCustomerRabateAmount(calculationDevided.getAeCustomerRabateAmount());
                    e.setActualDiscountRatio(calculationDevided.getActualDiscountRatio());
                    e.setCustomerRebateRate(calculationDevided.getCustomerRebateRate());
                }

            });
        }
        return excutionOrders;
    }

    /**
     * 审批回调
     *
     * @param approvalFlowDTO 流程对对象
     * @param status          最后节点的同意 false 拒绝
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approvalCallback(ApprovalFlowDTO approvalFlowDTO, Boolean status) {
        ContractExcutionOrder excutionOrder = contractExcutionOrderMapper.selectById(approvalFlowDTO.getSrcId());
        BusinessAssert.notNull(excutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        approvalFlowDTO.setSrcCode(excutionOrder.getExcuteCode());
        approvalFlowDTO.addSubmitInfoIfNull(excutionOrder);
        ApprovalEnum approvalEnum = ApprovalEnum.getEnumByExcutionOrderType(excutionOrder.getType());
        if (Objects.isNull(status)) {
            //驳回至【财务审核】节点的时候，清空【财务确认分成金额】、【打款方式】、【开票方式】
            if (EventTypeEnums.REJECTED.getCode().equals(approvalFlowDTO.getEventType())) {
                if (StringUtils.contains(approvalFlowDTO.getNodeName(), FINANCE_APPROVAL)) {
                    CalculationDevided cdEntity = calculationDevidedMapper.getByExecuteId(excutionOrder.getId());;
                    BusinessAssert.notNull(cdEntity, McnErrorCode.DATA_NOT_FOUND);
                    contractExcutionOrderMapper.updateByNoStrategy(Wrappers.<ContractExcutionOrder>lambdaUpdate()
                            .set(ContractExcutionOrder::getCustomerInvoiceWay, null)
                            .set(ContractExcutionOrder::getAccountId, null)
                            .set(ContractExcutionOrder::getAccountType, null)
                            .set(ContractExcutionOrder::getPaidWay, null)
                            .set(ContractExcutionOrder::getHandlingFeeRate, null)
                            .set(ContractExcutionOrder::getUpdateBy, approvalFlowDTO.getUserId())
                            .set(ContractExcutionOrder::getUpdateName, approvalFlowDTO.getUserName())
                            .set(ContractExcutionOrder::getUpdateDate, new Date())
                            .eq(ContractExcutionOrder::getId, excutionOrder.getId())
                    );
                    //操作日志
                    EventPublisher.post(OperateLogEvent.builder().businessId(excutionOrder.getId())
                            .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                            .compare(excutionOrder, contractExcutionOrderMapper.selectById(excutionOrder.getId())).build());
                    calculationDevidedMapper.updateByNoStrategy(Wrappers.<CalculationDevided>lambdaUpdate()
                            .set(CalculationDevided::getFinanceDevidedAmount, null)
                            .set(CalculationDevided::getAmountReceivable, null)
                            .set(CalculationDevided::getFinanceCulturalTax, null)
                            .set(CalculationDevided::getFinanceDevidedRemark, null)
                            .set(CalculationDevided::getUpdateBy, approvalFlowDTO.getUserId())
                            .set(CalculationDevided::getUpdateName, approvalFlowDTO.getUserName())
                            .set(CalculationDevided::getUpdateDate, new Date())
                            .eq(CalculationDevided::getId, cdEntity.getId())
                    );
                    //操作日志
                    EventPublisher.post(OperateLogEvent.builder().businessId(excutionOrder.getId())
                            .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                            .compare(cdEntity, calculationDevidedMapper.getByExecuteId(excutionOrder.getId())).build());
                }
            }
            //审批流配置-接入待办
        } else {
            Integer approvalStatus = status ? ExcutionApprovalStatusEnum.PASSED.code() : ExcutionApprovalStatusEnum.REJECTED.code();
            Date now = new Date();
            LambdaUpdateWrapper<ContractExcutionOrder> lambdaUpdateWrapper = Wrappers.<ContractExcutionOrder>lambdaUpdate()
                    .eq(ContractExcutionOrder::getId, excutionOrder.getId())
                    .set(ContractExcutionOrder::getUpdateBy, approvalFlowDTO.getUserId())
                    .set(ContractExcutionOrder::getUpdateName, approvalFlowDTO.getUserName())
                    .set(ContractExcutionOrder::getUpdateDate, now)
                    .set(ExcutionApprovalStatusEnum.isPassed(approvalStatus), ContractExcutionOrder::getTransitDate, now);
            //是否需要发MQ
            boolean needSendMq = false;
            CalculationDevided cdEntity = calculationDevidedMapper.getByExecuteId(excutionOrder.getId());
            BusinessAssert.notNull(cdEntity, McnErrorCode.NO_CALCULATION_DEVIDED);
            if (ExcutionApprovalStatusEnum.REJECTED.code().equals(approvalStatus)) {
                lambdaUpdateWrapper.set(ContractExcutionOrder::getCustomerInvoiceWay, null)
                        .set(ContractExcutionOrder::getAccountId, null)
                        .set(ContractExcutionOrder::getAccountType, null)
                        .set(ContractExcutionOrder::getPaidWay, null)
                        .set(ContractExcutionOrder::getHandlingFeeRate, null);
                calculationDevidedMapper.updateByNoStrategy(Wrappers.<CalculationDevided>lambdaUpdate()
                        .set(CalculationDevided::getFinanceDevidedAmount, null)
                        .set(CalculationDevided::getAmountReceivable, null)
                        .set(CalculationDevided::getFinanceCulturalTax, null)
                        .set(CalculationDevided::getFinanceDevidedRemark, null)
                        .eq(CalculationDevided::getId, cdEntity.getId()));
            } else if (ExcutionApprovalStatusEnum.isPassed(approvalStatus)) {
                IncomeContract incomeContract = incomeContractMapper.selectById(excutionOrder.getIncomeContractId());
                BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
                //只有单笔打款或收款才会生成费用
                if (SettlementMethodEnum.isSingleRemittance(cdEntity.getSettlementMethod()) || SettlementMethodEnum.isReceivePayment(cdEntity.getSettlementMethod())) {
                    needSendMq = true;
                }
                //是否直接已打款 - 收入合同回款金额补执行单总金额
                if(SettlementMethodEnum.isReceivePayment(cdEntity.getSettlementMethod()) && ObjectUtils.defaultIfNull(cdEntity.getAmountReceivable(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) == 0) {
                    approvalStatus = ExcutionApprovalStatusEnum.PAID.getCode();
                } else if(SettlementMethodEnum.isSingleRemittance(cdEntity.getSettlementMethod()) && ObjectUtils.defaultIfNull(cdEntity.getFinanceDevidedAmount(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) == 0) {
                    approvalStatus = ExcutionApprovalStatusEnum.PAID.getCode();
                }
                if(this.changePaybackIfNecessary(incomeContract, excutionOrder, cdEntity)) {
                    lambdaUpdateWrapper.set(ContractExcutionOrder::getPaybackStatus, NumberCst.TWO)
                            .set(ContractExcutionOrder::getPaybackAmount, BigDecimal.ZERO)
                            .set(ContractExcutionOrder::getPaybackDate, now);
                    this.updateContractPayback(incomeContract.getId(), excutionOrder, true);
                }
                //解除意向单关联
                this.writeBackIntentionOrder(excutionOrder);
            }
            //更新执行单
            contractExcutionOrderMapper.updateByNoStrategy(lambdaUpdateWrapper.set(ContractExcutionOrder::getApprovalStatus, approvalStatus));
            if (needSendMq) {
                //审批通过后生成费用推送财务系统
                excutionOrderMessageProducer.sendRecordToMq(excutionOrder.getId());
            }
            //操作日志-执行单
            EventPublisher.post(OperateLogEvent.builder().businessId(excutionOrder.getId())
                    .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                    .compare(excutionOrder, contractExcutionOrderMapper.selectById(excutionOrder.getId()))
                    .build(approvalFlowDTO.getUserId(), approvalFlowDTO.getUserName()));
            //操作日志-计算分成
            EventPublisher.post(OperateLogEvent.builder().businessId(excutionOrder.getId())
                    .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                    .compare(cdEntity, calculationDevidedMapper.getByExecuteId(excutionOrder.getId())).build());
            //审批通知
            approvalFlowService.sendNotify(approvalFlowDTO, excutionOrder.getId(), excutionOrder.getExcuteCode(), approvalEnum, status, excutionOrder.getApprovalBy(), excutionOrder.getApprovalName());
        }
    }

    /**
     * 更新合同回款
     * @param incomeContractId
     * @param excutionOrder
     * @param isAdd
     */
    private void updateContractPayback(Long incomeContractId, ContractExcutionOrder excutionOrder, boolean isAdd) {
        IncomeContract incomeContract = incomeContractMapper.selectOneForUpdate(Wrappers.lambdaQuery(IncomeContract.class)
                .eq(IncomeContract::getId, incomeContractId).eq(IncomeContract::getIsDelete, NumberCst.ZERO));
        BigDecimal targetPayBackAmount = null;
        if(isAdd) {
            targetPayBackAmount = ObjectUtils.defaultIfNull(incomeContract.getPayBackAmount(), BigDecimal.ZERO)
                    .add(ObjectUtils.defaultIfNull(excutionOrder.getActualQuotedPrice(), BigDecimal.ZERO));
        } else {
            targetPayBackAmount = ObjectUtils.defaultIfNull(incomeContract.getPayBackAmount(), BigDecimal.ZERO)
                    .subtract(ObjectUtils.defaultIfNull(excutionOrder.getActualQuotedPrice(), BigDecimal.ZERO));
        }
        IncomeContract beforeIncomeContract = new IncomeContract();
        beforeIncomeContract.setId(incomeContract.getId());
        beforeIncomeContract.setPayBackAmount(incomeContract.getPayBackAmount());
        beforeIncomeContract.setPayBackStatus(incomeContract.getPayBackStatus());
        beforeIncomeContract.setPayBackDate(incomeContract.getPayBackDate());
        IncomeContract updateIncomeContract = new IncomeContract();
        updateIncomeContract.setId(incomeContract.getId());
        updateIncomeContract.setPayBackAmount(targetPayBackAmount);
        updateIncomeContract.setPayBackDate(new Date());
        BigDecimal businessAmount = ObjectUtils.defaultIfNull(incomeContract.getBusinessAmount(), BigDecimal.ZERO);
        if (CommonUtil.greaterThanZero(businessAmount) && BigDecimal.ZERO.compareTo(updateIncomeContract.getPayBackAmount()) == 0) {
            updateIncomeContract.setPayBackStatus(NumberCst.ZERO);
            updateIncomeContract.setPayBackDate(null);
        } else if (businessAmount.compareTo(updateIncomeContract.getPayBackAmount()) == 1) {
            updateIncomeContract.setPayBackStatus(NumberCst.ONE);
        } else if (businessAmount.compareTo(updateIncomeContract.getPayBackAmount()) == 0) {
            if(IncomeContractTypeEnum.isLiveContract(incomeContract.getContractType()) && !"0".equals(incomeContract.getOfflineCommissionRate())
                    && !OfflineCommissionSettleStatusEnum.ALL_PAYBACK.getCode().equals(incomeContract.getOfflineCommissionSettleStatus())) {
                updateIncomeContract.setPayBackStatus(NumberCst.ONE);
            } else {
                updateIncomeContract.setPayBackStatus(NumberCst.TWO);
            }
        } else {
            updateIncomeContract.setPayBackStatus(NumberCst.TWO);
        }
        incomeContractMapper.updateById(updateIncomeContract);
        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(incomeContract.getId())
                .businessType(LogBusinessTypeEnum.INCOME_CONTRACT)
                .compare(beforeIncomeContract,  updateIncomeContract)
                .build(UserVoContextHolder.getUserId(), UserVoContextHolder.getUserName()));
    }

    /**
     * 是否需要变更回款信息
     * @param incomeContract
     * @param excutionOrder
     * @param cdEntity
     * @return
     */
    private boolean changePaybackIfNecessary(IncomeContract incomeContract, ContractExcutionOrder excutionOrder, CalculationDevided cdEntity) {
        //财务应收金额为0且结算方式=收款
        if (ObjectUtils.defaultIfNull(cdEntity.getAmountReceivable(), BigDecimal.ZERO).compareTo(BigDecimal.ZERO) == 0 &&
                SettlementMethodEnum.isReceivePayment(cdEntity.getSettlementMethod())) {
            if(IncomeContractTypeEnum.isFormalContract(incomeContract.getContractType())) {
                //（收入合同后置）是否账号入驻为否时，生成一笔应收费用（费用类型：18形式合同费）
                return true;
            } else if(IncomeContractTypeEnum.isLiveContract(incomeContract.getContractType()) && ObjectUtils.defaultIfNull(excutionOrder.getPlatformReport(), Boolean.FALSE).booleanValue()) {
                //生成一笔 线上下单未入驻红人框架广告费
                return true;
            }
        }
        return false;
    }

    /**
     * 校验导入参数
     *
     * @param inputList
     * @return
     */
    private List<ExcutionOrderBatchConfirmOutputDTO> verifyImportFinanceConfirm(Map<String, AccountInfoVO> accountInfoVoMap, List<ExcutionOrderBatchConfirmInputDTO> inputList) {
        List<ExcutionOrderBatchConfirmOutputDTO> outputList = new ArrayList<>();
        Set<String> repeatedExcuteCodeSet = new HashSet<>();
        //查执行单
        List<String> excuteCodes = inputList.stream().map(ExcutionOrderBatchConfirmInputDTO::getExcuteCode).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
        List<ContractExcutionOrder> excutionOrderList = CommonUtil.partitionList(excuteCodes, McnConstant.MAX_INSERT_SIZE,
                (codes) ->  contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .in(ContractExcutionOrder::getExcuteCode, codes).eq(ContractExcutionOrder::getIsDelete, Boolean.FALSE)));
        Map<String, ContractExcutionOrder> excutionOrderMap = CommonUtil.defaultList(excutionOrderList).stream().collect(Collectors.toMap(ContractExcutionOrder::getExcuteCode, Function.identity()));
        //查计算分成
        Map<String, CalculationDevided> cdMap = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(excuteCodes), () ->
                CommonUtil.defaultList(calculationDevidedMapper.selectList(Wrappers.lambdaQuery(CalculationDevided.class).in(CalculationDevided::getExcutionOrderCode, excuteCodes)
                        .eq(CalculationDevided::getIsDelete, Boolean.FALSE))).stream().collect(Collectors.toMap(k -> k.getExcutionOrderCode(), v -> v)), Collections.EMPTY_MAP);
        for (ExcutionOrderBatchConfirmInputDTO input : inputList) {
            ExcutionOrderBatchConfirmOutputDTO output = new ExcutionOrderBatchConfirmOutputDTO();
            BeanUtils.copyProperties(input, output);
            output.setContractExcutionOrder(excutionOrderMap.get(output.getExcuteCode()));
            output.setCalculationDevided(cdMap.get(output.getExcuteCode()));
            if(StringUtils.isBlank(output.getExcuteCode())) {
                output.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, output.getFailedReason(), "【执行单号】必填"));
            } else {
                if (repeatedExcuteCodeSet.contains(output.getExcuteCode())) {
                    output.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, output.getFailedReason(), "【执行单号】重复"));
                } else {
                    repeatedExcuteCodeSet.add(output.getExcuteCode());
                    ContractExcutionOrder entity = output.getContractExcutionOrder();
                    if (entity == null) {
                        output.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, output.getFailedReason(), "【执行单号】系统查询不到"));
                    } else {
                        output.setId(entity.getId());
                        output.setFlowStatus(entity.getApprovalStatus());
                        if (!ApprovalStatusEnum.isApproval(entity.getApprovalStatus())) {
                            output.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, output.getFailedReason(), "单据状态错误须是【审批中】"));
                        }
                    }
                }
            }
            outputList.add(output);
        }
        outputList.forEach(e -> {
            if (Objects.nonNull(e.getCalculationDevided())) {
                CalculationDevided cd = e.getCalculationDevided();
                if(SettlementMethodEnum.isRemittance(cd.getSettlementMethod())) {
                    //校验-财务确认分成金额
                    if(Objects.isNull(e.getFinanceDevidedAmount())) {
                        e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "【财务确认分成金额（元）】必填"));
                    } else {
                        if (e.getFinanceDevidedAmount().compareTo(BigDecimal.ZERO) == -1 || e.getFinanceDevidedAmount().scale() > 2) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "【财务确认分成金额（元）】须 >=0 且 小数位<=2！"));
                        }
                    }
                    //校验-财务确认文建税
                    if(Objects.isNull(e.getFinanceCulturalTax())) {
                        e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "【财务确认文建税（元）】必填"));
                    } else {
                        if (e.getFinanceCulturalTax().compareTo(BigDecimal.ZERO) == -1 || e.getFinanceCulturalTax().scale() > 2) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "【财务确认文建税（元）】须 >=0 且 小数位<=2！"));
                        }
                    }
                    boolean eq1 = ObjectUtils.defaultIfNull(e.getFinanceDevidedAmount(), BigDecimal.ZERO).compareTo(ObjectUtils.defaultIfNull(cd.getAeDevidedAmount(), BigDecimal.ZERO)) != 0;
                    boolean eq2 = ObjectUtils.defaultIfNull(e.getFinanceCulturalTax(), BigDecimal.ZERO).compareTo(ObjectUtils.defaultIfNull(cd.getAeCulturalTax(), BigDecimal.ZERO)) != 0;
                    if(StringUtils.isBlank(e.getFinanceDevidedRemark())) {
                        if(eq1 && eq2) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "财务确认分成金额≠AE确认分成金额，财务确认文建税≠AE确认文建税，请在“财务备注”中进行差异说明！"));
                        } else if(eq1) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "财务确认分成金额≠AE确认分成金额，请在“财务备注”中进行差异说明！"));
                        } else if(eq2) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "财务确认文建税≠AE确认文建税，请在“财务备注”中进行差异说明！"));
                        }
                    }
                    //财务财务审批节点，结算方式为【单笔打款】时，需要录入【开票方式】、【打款方式】两个字段，且需必填校验，Excel批量审核和页面操作审核，均需校验。
                    if (SettlementMethodEnum.isSingleRemittance(cd.getSettlementMethod())) {
                        //校验-开票方式
                        if (StringUtils.isBlank(e.getCustomerInvoiceWay())) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "请录入开票方式！"));
                        } else if (!StringUtils.equalsAny(e.getCustomerInvoiceWay(), McnConstant.INOVICE_WAY_ISSUED, McnConstant.INOVICE_WAY_AFTER)) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "开票方式错误，请录入开票OR后补票！"));
                        }
                        //校验-打款方式
                        if (StringUtils.isBlank(e.getPaidWay())) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "请录入打款方式！"));
                        } else if (!accountInfoVoMap.containsKey(e.getPaidWay())) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "请录入正确的打款方式！"));
                        } else {
                            e.setAccountInfoVO(accountInfoVoMap.get(e.getPaidWay()));
                        }
                    }
                } else if(SettlementMethodEnum.isReceivePayment(cd.getSettlementMethod())) {
                    //校验-财务确认应收金额
                    if(Objects.isNull(e.getAmountReceivable())) {
                        e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "【财务确认应收金额（元）】必填"));
                    } else {
                        if (e.getAmountReceivable().compareTo(BigDecimal.ZERO) == -1 || e.getAmountReceivable().scale() > 2) {
                            e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "【财务确认应收金额（元）】须 >=0 且 小数位<=2！"));
                        }
                    }
                    if(ObjectUtils.defaultIfNull(e.getAmountReceivable(), BigDecimal.ZERO).compareTo(ObjectUtils.defaultIfNull(cd.getAeReceivableAmount(), BigDecimal.ZERO)) != 0 &&
                            StringUtils.isBlank(e.getFinanceDevidedRemark())) {
                        e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "财务确认应收金额≠AE确认应收金额，请在“财务备注”中进行差异说明！"));
                    }
                }
            }
        });
        return outputList;
    }

    /**
     * @param outputList
     */
    private void approvalInfoForConfirmDevided(List<ExcutionOrderBatchConfirmOutputDTO> outputList) {
        //补全审批信息
        if (CollectionUtils.isNotEmpty(outputList)) {
            List<Long> srcIds = outputList.stream().filter(t -> Objects.nonNull(t.getId())).map(ExcutionOrderBatchConfirmOutputDTO::getId).collect(Collectors.toList());
            Map<Long, ApprovalNodeVO> noteMap = approvalFlowService.getCurrentApprovalNodes(srcIds, ApprovalEnum.getExecutionOrderProcessIds());
            for (ExcutionOrderBatchConfirmOutputDTO e : outputList) {
                if(Objects.nonNull(e.getId()) && CommonUtil.containsKey(noteMap, e.getId())) {
                    ApprovalNodeVO approvalNodeVO = noteMap.get(e.getId());
                    e.setApprovalId(approvalNodeVO.getApprovalId());
                    e.setCurrentNodeName(approvalNodeVO.getNodeName());
                }
                //判断是否执行流程校验
                if (Objects.isNull(e.getId()) || !ApprovalStatusEnum.isApproval(e.getFlowStatus()) || Objects.isNull(e.getApprovalId())) {
                    continue;
                }
                //判断审批节点
                if (!StringUtils.equals(e.getCurrentNodeName(), "财务审核")) {
                    e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "审批节点错误，须是【财务审核】"));
                }
            }
        }
    }

    /**
     * @param outputList
     */
    private void approvalInfoForBatchApproval(List<ExcutionOrderBatchApprovalOutputDTO> outputList) {
        //补全审批信息
        if (CollectionUtils.isNotEmpty(outputList)) {
            List<Long> srcIds = outputList.stream().filter(t -> Objects.nonNull(t.getId()) && ExcutionApprovalStatusEnum.isApproval(t.getApprovalStatus())
            ).map(ExcutionOrderBatchApprovalOutputDTO::getId).collect(Collectors.toList());
            Map<Long, ApprovalNodeVO> noteMap = approvalFlowService.getCurrentApprovalNodes(srcIds, ApprovalEnum.getExecutionOrderProcessIds());
            for (ExcutionOrderBatchApprovalOutputDTO e : outputList) {
                if(!ExcutionApprovalStatusEnum.isApproval(e.getApprovalStatus())) {
                    continue;
                }
                if(Objects.nonNull(e.getId()) && CommonUtil.containsKey(noteMap, e.getId())) {
                    ApprovalNodeVO approvalNodeVO = noteMap.get(e.getId());
                    e.setApprovalId(approvalNodeVO.getApprovalId());
                    e.setNodeName(approvalNodeVO.getNodeName());
                }
                //判断是否执行流程校验
                if (Objects.isNull(e.getId()) || Objects.isNull(e.getApprovalId())) {
                    continue;
                }
                if(StringUtils.equalsAny(e.getApprovalResult(), "拒绝", "驳回")) {
                    continue;
                }
                if (StringUtils.equals(e.getNodeName(), "财务审核")) {
                    e.setFailedReason(CommonUtil.joinWith(SeparatorCst.LINE_BREAK, e.getFailedReason(), "请用财务批量确认分成进行审批！"));
                }
            }
        }
    }
    /**
     * 反写意向单
     * @param excutionOrder
     */
    private void writeBackIntentionOrder(ContractExcutionOrder excutionOrder) {
        DocIntentionOrder docIntentionOrder = intentionOrderMapper.selectOne(Wrappers.lambdaQuery(DocIntentionOrder.class)
                .eq(DocIntentionOrder::getExcutionOrderId, excutionOrder.getId())
                .eq(DocIntentionOrder::getIsDelete, NumberCst.ZERO));
        if(Objects.nonNull(docIntentionOrder)) {
            intentionOrderMapper.updateByNoStrategy(Wrappers.lambdaUpdate(DocIntentionOrder.class)
                    .eq(DocIntentionOrder::getId, docIntentionOrder.getId())
                    .set(DocIntentionOrder::getStatus, IntentionOrderStatusEnum.FINNISHED.getCode())
                    //执行单总金额需要更新到意向单金额
                    .set(DocIntentionOrder::getActualAmount, excutionOrder.getActualQuotedPrice())
                    .set(DocIntentionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(DocIntentionOrder::getUpdateName, UserVoContextHolder.getUserName())
                    .set(DocIntentionOrder::getUpdateDate, new Date()));
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(docIntentionOrder.getId())
                    .businessType(LogBusinessTypeEnum.INTENTION_ORDER)
                    .compare(docIntentionOrder, intentionOrderMapper.selectById(docIntentionOrder.getId()))
                    .build());
        }
    }

    /**
     * 直播合同检验执行单金额
     *
     * @param contractExecutionOrders 执行单
     * @param advAmtTotal             合同金额
     */
    private void verifyLiveContractExecutionAmount(List<ContractExcutionOrder> contractExecutionOrders, BigDecimal advAmtTotal) {
//        if (Objects.nonNull(advAmtTotal)) {
//            if (CollectionUtils.isNotEmpty(contractExecutionOrders)) {
//                BigDecimal reduce = contractExecutionOrders.stream().filter(o -> !ExcutionApprovalStatusEnum.INVALID.getCode().equals(o.getApprovalStatus())).map(ContractExcutionOrder::getActualQuotedPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
//                BusinessAssert.isTrue(reduce.compareTo(adAmount) == 0, McnErrorCode.MUST_BE_EQUAL_TO_AD_AMOUNT);
//            } else {
//                BusinessAssert.isTrue(adAmount.compareTo(new BigDecimal(0)) == 0, McnErrorCode.MUST_BE_EQUAL_TO_AD_AMOUNT);
//            }
//        }
        if (Objects.nonNull(advAmtTotal) && CollectionUtils.isNotEmpty(contractExecutionOrders)) {
            BigDecimal reduce = contractExecutionOrders.stream().filter(o -> !ExcutionApprovalStatusEnum.INVALID.getCode().equals(o.getApprovalStatus())).map(ContractExcutionOrder::getActualQuotedPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            log.info("执行单总金额之和3:{},",reduce+"｜"+advAmtTotal);
            if (reduce.compareTo(advAmtTotal) != 0){
                throw new BusinessException(McnErrorCode.AMOUNT_OF_THE_EXECUTIO_NMUST_BE_EQUAL);
            }
        }
    }

    /**
     * 非框架合同&非直播合同 才校验执行单金额
     *
     * @param contractExecutionOrders
     * @param businessAmount
     */
    private void verifyExcutionAmount(List<ContractExcutionOrder> contractExecutionOrders, BigDecimal businessAmount) {
        if (Objects.isNull(businessAmount) || CollectionUtils.isEmpty(contractExecutionOrders)) {
            return;
        }
        BigDecimal reduce = contractExecutionOrders.stream().filter(o -> !ExcutionApprovalStatusEnum.INVALID.getCode().equals(o.getApprovalStatus())).map(ContractExcutionOrder::getActualQuotedPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        BusinessAssert.isTrue(reduce.compareTo(businessAmount) == 0, McnErrorCode.EXCEEDING_CONTRACT_AMOUNT);
    }

    /**
     * 根据导出参数选择不同的导出字段
     */
    @Override
    public List<ExcelCustom> chooseExportField(String exportTypeStr) {
        List<ExcelCustom> excelCustomList = new ArrayList<>();
        List<String> exportTypeString = Arrays.asList(exportTypeStr.split(","));
        List<Integer> exportTypes = exportTypeString.stream().map(Integer::valueOf).collect(Collectors.toList());
        for (Integer exportType : exportTypes) {
            ExcutionExportTypeEnum exportTypeEnum = ExcutionExportTypeEnum.getByType(exportType);
            if(Objects.isNull(exportTypeEnum)) {
                continue;
            }
            switch (exportTypeEnum) {
                case BASIC_INFO:
                    excelCustomList.add(new ExcelCustom("excuteCode", "正式执行单号"));
                    excelCustomList.add(new ExcelCustom("approvalStatusName", "正式执行单单据状态"));
                    excelCustomList.add(new ExcelCustom("customerName", "客户名称"));
                    excelCustomList.add(new ExcelCustom("platNickName", "红人平台昵称"));
                    excelCustomList.add(new ExcelCustom("starName", "红人真实姓名"));
                    //就得是cooperate_brand_name 对应中文名称
                    excelCustomList.add(new ExcelCustom("brandName", "品牌"));
                    excelCustomList.add(new ExcelCustom("productName", "产品名称"));
                    excelCustomList.add(new ExcelCustom("platformName", "发布平台"));
                    excelCustomList.add(new ExcelCustom("publishForm", "发布形式"));
                    excelCustomList.add(new ExcelCustom("publishDate", "发布日期"));
                    excelCustomList.add(new ExcelCustom("realPublishDate", "实际发布日期"));
                    excelCustomList.add(new ExcelCustom("haveLinkCommand", "是否挂车/橱窗/组件"));
                    excelCustomList.add(new ExcelCustom("platformReport", "是否平台下单"));
                    excelCustomList.add(new ExcelCustom("orderPlatform", "下单平台"));
                    excelCustomList.add(new ExcelCustom("platformOrderCode", "平台订单号"));
                    excelCustomList.add(new ExcelCustom("isLiveAd", "是否直播合作广告"));
                    excelCustomList.add(new ExcelCustom("haveDiscountApproval", "是否有折扣返点审批"));
                    excelCustomList.add(new ExcelCustom("excutorName", "执行人"));
                    excelCustomList.add(new ExcelCustom("coordinatorName", "执行统筹人"));
                    excelCustomList.add(new ExcelCustom("paybackStatus", "执行单回款状态"));
                    excelCustomList.add(new ExcelCustom("paybackDate", "回款时间"));
                    excelCustomList.add(new ExcelCustom("commissionSettleStatus", "AE提成结算状态"));
                    excelCustomList.add(new ExcelCustom("businessCommissionSettleStatus", "商务提成结算状态"));
                    excelCustomList.add(new ExcelCustom("rebateSettleStatus", "客户返点结算状态"));
                    excelCustomList.add(new ExcelCustom("createName", "执行单创建人"));
                    excelCustomList.add(new ExcelCustom("performanceSharerName", "业绩共享人"));
                    excelCustomList.add(new ExcelCustom("createDate", "执行单创建时间"));
                    excelCustomList.add(new ExcelCustom("remark", "执行单备注"));
                    excelCustomList.add(new ExcelCustom("intentionCode", "前置执行单号"));
                    excelCustomList.add(new ExcelCustom("incomeContractCode", "合同编号"));
                    excelCustomList.add(new ExcelCustom("businessAmount", "合同总金额（元）"));
                    excelCustomList.add(new ExcelCustom("contractType", "合同类型"));
                    excelCustomList.add(new ExcelCustom("signDate", "合同签订日期"));
                    excelCustomList.add(new ExcelCustom("companyContractSubject", "我司合同主体"));
                    excelCustomList.add(new ExcelCustom("contractApprovalStatus", "合同单据状态"));
                    excelCustomList.add(new ExcelCustom("contractPaybackStatus", "合同回款状态"));
                    break;

                case EXCUTE_FEEDBACK:
                    excelCustomList.add(new ExcelCustom("publishUrl", "发布链接"));
                    excelCustomList.add(new ExcelCustom("readQuantity", "阅读量"));
                    excelCustomList.add(new ExcelCustom("interactQuantity", "互动量"));
                    excelCustomList.add(new ExcelCustom("playQuantity", "播放量"));
                    excelCustomList.add(new ExcelCustom("conversionAmount", "转化金额（元）"));
                    break;

                case CALCULATION_DIVIDED:
                    excelCustomList.add(new ExcelCustom("isAllPlatform", "是否按执行结算"));
                    excelCustomList.add(new ExcelCustom("settlementMethod", "结算方式"));
                    excelCustomList.add(new ExcelCustom("settlementForm", "结算形式"));
                    excelCustomList.add(new ExcelCustom("accountName", "收款户名"));
                    excelCustomList.add(new ExcelCustom("studioPayment", "打款类型"));
                    //excelCustomList.add(new ExcelCustom("accountType", "账号类型"));
                    excelCustomList.add(new ExcelCustom("taxRate", "本单红人个税"));
                    excelCustomList.add(new ExcelCustom("accountNumber", "收款卡号"));
                    excelCustomList.add(new ExcelCustom("accountBank", "开户行"));
                    excelCustomList.add(new ExcelCustom("accountBranchBank", "开户支行"));
                    excelCustomList.add(new ExcelCustom("accountProvince", "开户省"));
                    excelCustomList.add(new ExcelCustom("accountCity", "开户市"));
                    excelCustomList.add(new ExcelCustom("accountIdCard", "收款账户身份证号"));
                    excelCustomList.add(new ExcelCustom("accountPhone", "收款账户手机号"));

                    excelCustomList.add(new ExcelCustom("actualQuotedPrice", "执行单总收入（元）"));
                    excelCustomList.add(new ExcelCustom("cardRatePrice", "刊例原价（元）"));
                    excelCustomList.add(new ExcelCustom("realAmount", "内容实际报价（元）"));
                    excelCustomList.add(new ExcelCustom("otherAmount", "其他加价收入（元）"));
                    excelCustomList.add(new ExcelCustom("otherAmountRemark", "其他加价收入说明"));
                    excelCustomList.add(new ExcelCustom("platformFee", "平台手续费/微任务金额（元）"));
                    excelCustomList.add(new ExcelCustom("otherFee", "机酒差旅费用（元）"));
                    excelCustomList.add(new ExcelCustom("specialFeeRemark", "机酒差旅费用说明"));
                    excelCustomList.add(new ExcelCustom("subsidyIncomeAmount", "其他补贴性收入（元）"));
                    excelCustomList.add(new ExcelCustom("subsidyIncomeRemark", "其他补贴性收入说明"));
                    excelCustomList.add(new ExcelCustom("aeCustomerRabateRate", "内容报价返点比例（%）"));
                    excelCustomList.add(new ExcelCustom("aeCustomerRabateAmount", "内容报价返点金额（元）"));
                    excelCustomList.add(new ExcelCustom("actualDiscountRatio", "本单实际优惠比例（%）"));
                    //excelCustomList.add(new ExcelCustom("customerRebateAmount", "客户固定优惠比例（%）"));
                    excelCustomList.add(new ExcelCustom("cooperationContent", "合作内容"));
                    excelCustomList.add(new ExcelCustom("inSystemAdmin", "红人是否入驻"));
                    excelCustomList.add(new ExcelCustom("starDevidedRate", "红人分成比例（%）"));
                    excelCustomList.add(new ExcelCustom("handPrice", "本单固定到手价(元)"));
                    excelCustomList.add(new ExcelCustom("sysDevidedAmount", "系统计算分成金额（元）"));
                    excelCustomList.add(new ExcelCustom("aeDevidedAmount", "AE确认分成金额(元)"));
                    excelCustomList.add(new ExcelCustom("financeDevidedAmount", "财务确认分成金额(元)"));
                    excelCustomList.add(new ExcelCustom("aeReceivableAmount", "AE确认应收金额（元）"));
                    excelCustomList.add(new ExcelCustom("amountReceivable", "财务确认应收金额（元）"));
                    excelCustomList.add(new ExcelCustom("sysCulturalTax", "系统计算文建税（元）"));
                    excelCustomList.add(new ExcelCustom("aeCulturalTax", "AE确认文建税（元）"));
                    excelCustomList.add(new ExcelCustom("financeCulturalTax", "财务确认文建税（元）"));
                    excelCustomList.add(new ExcelCustom("aeDevidedRemark", "AE备注"));
                    excelCustomList.add(new ExcelCustom("financeDevidedRemark", "财务备注"));
                    excelCustomList.add(new ExcelCustom("paidDate", "打款至红人日期"));
                    excelCustomList.add(new ExcelCustom("customerInvoiceWay", "开票方式"));
                    excelCustomList.add(new ExcelCustom("paidWay", "打款方式"));
                    excelCustomList.add(new ExcelCustom("paidRemark", "打款备注"));
                    excelCustomList.add(new ExcelCustom("clearNo", "回款核销单号"));
                    excelCustomList.add(new ExcelCustom("clearDate", "回款核销日期"));
                    excelCustomList.add(new ExcelCustom("recordSeqNo", "回款核销实收付流水号"));
                    excelCustomList.add(new ExcelCustom("arapDate", "回款流水到账日期"));
                    excelCustomList.add(new ExcelCustom("collectionUnit", "回款流水对方主体名称"));
                    excelCustomList.add(new ExcelCustom("paybackCompany", "回款流水我司主体名称"));
                    excelCustomList.add(new ExcelCustom("paybackArrivalAmount", "回款流水到账金额"));
                    break;
                default:
                    break;
            }
        }
        return excelCustomList;
    }


    @Override
    public void updatePayback(ChargeClearCallback dto, ContractExcutionOrder excutionOrder, BigDecimal totalAmount, boolean needUpdatePaid) {
        MessageTopicEnum topicEnum = MessageTopicEnum.PAYBACK_CALLBACK_ZXD;
        //是否冲销
        boolean isChargeAgainst = ObjectUtils.defaultIfNull(dto.getIsChargeAgainst(), dto.getPaybackAmount().compareTo(BigDecimal.ZERO) == -1);
        Date now = new Date();
        //更新收入合同回款金额
        ContractExcutionOrder updateEntity = new ContractExcutionOrder();
        updateEntity.setPaybackAmount(ObjectUtils.defaultIfNull(excutionOrder.getPaybackAmount(), BigDecimal.ZERO).add(dto.getPaybackAmount()));
        BusinessAssert.isTrue(updateEntity.getPaybackAmount().compareTo(BigDecimal.ZERO) != -1,
                McnErrorCode.PARAM_ERROR, String.format("【%s】计算后回款金额为负数", topicEnum.getDesc()));
        if(totalAmount.compareTo(BigDecimal.ZERO) <= 0 ) {
            updateEntity.setPaybackStatus(isChargeAgainst ? NumberCst.ZERO : NumberCst.TWO);
        } else {
            if(BigDecimal.ZERO.compareTo(updateEntity.getPaybackAmount()) == 0) {
                if(needUpdatePaid) {
                    updateEntity.setApprovalStatus(ExcutionApprovalStatusEnum.PASSED.getCode());
                }
                updateEntity.setPaybackStatus(NumberCst.ZERO);
            } else if (totalAmount.compareTo(updateEntity.getPaybackAmount()) == 1) {
                if(needUpdatePaid) {
                    updateEntity.setApprovalStatus(ExcutionApprovalStatusEnum.PASSED.getCode());
                }
                updateEntity.setPaybackStatus(NumberCst.ONE);
            } else if (totalAmount.compareTo(updateEntity.getPaybackAmount()) == 0) {
                updateEntity.setPaybackStatus(NumberCst.TWO);
                if(needUpdatePaid) {
                    updateEntity.setApprovalStatus(ExcutionApprovalStatusEnum.PAID.getCode());
                }
            } else {
                //理论上不存在 回款金额大于线下佣金金额
                updateEntity.setPaybackStatus(NumberCst.TWO);
                if(needUpdatePaid) {
                    updateEntity.setApprovalStatus(ExcutionApprovalStatusEnum.PAID.getCode());
                }
            }
        }
        updateEntity.setPaybackDate(dto.getPaybackDate());
        updateEntity.setPaybackAmount(updateEntity.getPaybackAmount());
        dto.setTotalPaybackAmount(updateEntity.getPaybackAmount());
        String messageBody = JSONObject.toJSONString(dto);
        String messageKey = StringUtils.joinWith(isChargeAgainst ? "-" : "+", dto.getClearNo(), excutionOrder.getExcuteCode());
        String signature = CommonUtil.hmacMd5Hex(messageBody);
        MessageInfo messageInfo = MessageInfo.builder().messageTopic(topicEnum.name()).messageKey(messageKey)
                .tenantId(excutionOrder.getTenantId())
                .messageBody(messageBody).signature(signature).status(MessageStatusEnum.SUCCESS.getType()).build();
        if (!messageInfoService.addMessageInfo(messageInfo)) {
            MessageInfo entity = messageInfoService.selectOne(Wrappers.lambdaQuery(MessageInfo.class)
                    .eq(MessageInfo::getMessageTopic, topicEnum.name())
                    .eq(MessageInfo::getMessageKey, messageKey)
                    .eq(MessageInfo::getTenantId, excutionOrder.getTenantId())
                    .eq(MessageInfo::getIsDelete, Boolean.FALSE)
            );
            BusinessAssert.notNull(entity, String.format("【%s】数据幂等处理异常", topicEnum.getDesc()));
            //判断消息内容签名，如果相等，重复回调
            if (signature.equals(entity.getSignature())) {
                //也可以进一步比较金额
                return;
            }
            ChargeClearCallback payload = JSONObject.parseObject(entity.getMessageBody(), ChargeClearCallback.class);
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(),
                    String.format("【%s】重复请求！上次回调：核销单号=%s，金额=%s，执行单号=%s", topicEnum.getDesc(), payload.getClearNo(), payload.getPaybackAmount(), payload.getChargeSourceDetail()));
        }

        updateEntity.setId(excutionOrder.getId());
        updateEntity.setUpdateBy(dto.getOperatorId());
        updateEntity.setUpdateName(dto.getOperatorName());
        updateEntity.setUpdateDate(now);
        boolean result = contractExcutionOrderMapper.updateById(updateEntity) > 0;
        if(result){
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(excutionOrder.getId())
                    .businessType(LogBusinessTypeEnum.EXECUTION_ORDER)
                    .remark(dto.getClearNo())
                    .compare(excutionOrder, contractExcutionOrderMapper.selectById(excutionOrder.getId()))
                    .build());
        }
    }

    @Override
    public void updateBusinessCommissionSettleStatusByIds(List<Long> excuteIds, Integer sourceStatus, Integer targetStatus) {
        contractExcutionOrderMapper.updateByNoStrategy(Wrappers.<ContractExcutionOrder>lambdaUpdate()
                .set(ContractExcutionOrder::getBusinessCommissionSettleStatus, targetStatus)
                .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                .set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                .set(ContractExcutionOrder::getUpdateDate, new Date())
                .in(ContractExcutionOrder::getId, excuteIds)
                .eq(ContractExcutionOrder::getBusinessCommissionSettleStatus, sourceStatus));
    }

    @Override
    public List<ExcutionOrderUpdateDTO> getBatchSubmitData(List<Long> excuteIds, ExcutionApprovalStatusEnum allowStatusEnum) {
        List<ContractExcutionOrder> dataList = contractExcutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO).in(ContractExcutionOrder::getId, excuteIds));
        BusinessAssert.notEmpty(dataList, McnErrorCode.EXECUTION_NOT_EXISTS);
        if(dataList.stream().filter(e -> !allowStatusEnum.code().equals(e.getApprovalStatus())).count() > 0L) {
            String message = dataList.stream().filter(e -> !allowStatusEnum.code().equals(e.getApprovalStatus()))
                    .map(ContractExcutionOrder::getExcuteCode).collect(Collectors.joining("、", "单据状态必须为“"+allowStatusEnum.getDesc() + "”，请取消非该状态的执行单【", "】！"));
            throw new BusinessException(McnErrorCode.PARAM_ERROR.code(), message);
        }
        //计算分成
        Map<Long, CalculationDevided> calculationDevidedMap = CommonUtil.defaultList(calculationDevidedMapper.selectList(Wrappers.lambdaQuery(CalculationDevided.class)
                .in(CalculationDevided::getExcutionOrderId, excuteIds).in(CalculationDevided::getIsDelete, NumberCst.ZERO))).stream().collect(Collectors.toMap(CalculationDevided::getExcutionOrderId, calculationDevided -> calculationDevided));
        //执行反馈
        Map<Long, ExcuteFeedback> excuteFeedbackMap = CommonUtil.defaultList(excuteFeedbackMapper.selectList(Wrappers.lambdaQuery(ExcuteFeedback.class)
                .in(ExcuteFeedback::getExcutionOrderId, excuteIds).eq(ExcuteFeedback::getIsDelete, NumberCst.ZERO))).stream().collect(Collectors.toMap(ExcuteFeedback::getExcutionOrderId, excuteFeedback -> excuteFeedback));
        ExcutionOrderBatchSubmitVO confirmVO = new ExcutionOrderBatchSubmitVO();
        confirmVO.setTotalNum(dataList.size());
        List<ExcutionOrderUpdateDTO> updateList = new ArrayList<>(dataList.size());
        for(ContractExcutionOrder excutionOrder : dataList) {
            ExcutionOrderUpdateDTO excutionOrderUpdateDTO = new ExcutionOrderUpdateDTO();
            BeanUtils.copyProperties(excutionOrder, excutionOrderUpdateDTO);
            excutionOrderUpdateDTO.setCalculationDevided(CommonUtil.getMapValue(calculationDevidedMap, excutionOrder.getId()));
            excutionOrderUpdateDTO.setExcuteFeedback(CommonUtil.getMapValue(excuteFeedbackMap, excutionOrder.getId()));
            updateList.add(excutionOrderUpdateDTO);
        }
        return updateList;
    }

    /**
     * 重复提醒
     * @param contractExcutionOrder
     * @param excuteFeedback
     */
    private void remindDuplicateEntry(ContractExcutionOrder contractExcutionOrder, ExcuteFeedback excuteFeedback) {
        List<ContractExcutionOrder> repeatedContractExcutionOrders = contractExcutionOrderMapper.getRepeatedContractExcutionOrders(Lists.newArrayList(contractExcutionOrder.getId()),
                contractExcutionOrder.getStarPlatformInfoId(), contractExcutionOrder.getBrandName(),
                contractExcutionOrder.getRealAmount(), excuteFeedback.getRealPublishDate(), excuteFeedback.getRealPublishDate());
        if(CollectionUtils.isNotEmpty(repeatedContractExcutionOrders)) {
            StarPlatInfoVO starPlatInfoVO = starPlatformInfoService.getById(contractExcutionOrder.getStarPlatformInfoId());
            BusinessAssert.notNull(starPlatInfoVO, McnErrorCode.STAR_PLATOFRM_INFO_IS_NULL);
            String coperateBrandName = brandInfoService.getBrandNameByCode(contractExcutionOrder.getBrandName());
            List<KVPair<Long, String>> billList = repeatedContractExcutionOrders.stream().map(e -> new KVPair<>(e.getId(), e.getExcuteCode())).collect(Collectors.toList());
            throw new RepeatedDataExeception(McnErrorCode.EXCUTION_ORDER_EPEATED, new RepeatedExcutionOrderData(coperateBrandName, starPlatInfoVO.getPlatformName(),
                    DateUtils.formatDate(excuteFeedback.getRealPublishDate(), McnConstant.SHORT_DATE_FORMAT),
                    starPlatInfoVO.getPlatNickName(),contractExcutionOrder.getRealAmount(), billList
            ));
        }
    }

    /**
     * 获取或更新红人分成比例及系统参考分成
     * @param excutionOrderId
     * @param needUpdate
     * @return
     */
    @Override
    public DividedRateOrSysAmountVO getOrUpdateDividedRate(Long excutionOrderId, Date realPublishDate, boolean needUpdate) {
        ContractExcutionOrder contractExcutionOrder = contractExcutionOrderMapper.selectById(excutionOrderId);
        BusinessAssert.notNull(contractExcutionOrder, McnErrorCode.EXECUTION_NOT_EXISTS);
        if(Objects.isNull(realPublishDate)) {
            ExcuteFeedback excuteFeedback = excuteFeedbackMapper.getByExcuteId(contractExcutionOrder.getId());
            if(Objects.isNull(excuteFeedback)) {
                return null;
            }
            realPublishDate = excuteFeedback.getRealPublishDate();
        }
        StarContractDetail starContractDetail = starContractDetailMapper.getValidSignedContract(null, contractExcutionOrder.getStarPlatformInfoId(), realPublishDate);
        if(Objects.isNull(starContractDetail)) {
            StarPlatformInfo starPlatformInfo = starPlatformInfoService.selectById(contractExcutionOrder.getStarPlatformInfoId());
            BusinessAssert.notNull(starPlatformInfo, "红人平台信息不存在");
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), String.format("未匹配到该红人在「%s」的签约合同，请先补充该红人的签约合同信息", starPlatformInfo.getPlatformName()));
        }
        BigDecimal dividedRate = starContractDetail.getDividedRate();
        contractExcutionOrder.setDividedRate(dividedRate);
        contractExcutionOrder.setDividedRemark(StringUtils.defaultString(starContractDetail.getDividedRemark()));
        if(needUpdate) {
            //更新红人计算分成
            contractExcutionOrderMapper.updateByNoStrategy(Wrappers.<ContractExcutionOrder>lambdaUpdate()
                    .set(ContractExcutionOrder::getDividedRate, contractExcutionOrder.getDividedRate())
                    .set(ContractExcutionOrder::getDividedRemark, contractExcutionOrder.getDividedRemark())
                    .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                    .set(ContractExcutionOrder::getUpdateDate, new Date())
                    .eq(ContractExcutionOrder::getId, contractExcutionOrder.getId()));
        }
        CalculationDevided calculationDevided = calculationDevidedMapper.getByExecuteId(excutionOrderId);
        BigDecimal sysDevidedAmount = this.getSysDevidedAmount(contractExcutionOrder, calculationDevided);
        //系统计算文建税公式：（执行单总收入-（执行单总金额*平台服务费比例）-返点金额）
        OrderPlatformInfo orderPlatformInfo = orderPlatformInfoMapper.selectOne(Wrappers.lambdaQuery(OrderPlatformInfo.class)
                .eq(OrderPlatformInfo::getOrderPlatform, contractExcutionOrder.getOrderPlatform()).eq(OrderPlatformInfo::getIsDelete, NumberCst.ZERO));
        BigDecimal serivceFeeRate = BigDecimal.ZERO;
        if(Objects.nonNull(orderPlatformInfo)) {
            serivceFeeRate = ObjectUtils.defaultIfNull(orderPlatformInfo.getSerivceFeeRate(), BigDecimal.ZERO);
        }
        BigDecimal t1 = ObjectUtils.defaultIfNull(contractExcutionOrder.getActualQuotedPrice(), BigDecimal.ZERO).multiply(serivceFeeRate);
        BigDecimal t2 = ObjectUtils.defaultIfNull(contractExcutionOrder.getActualQuotedPrice(), BigDecimal.ZERO)
                .subtract(t1)
                .subtract(ObjectUtils.defaultIfNull(calculationDevided.getAeCustomerRabateAmount(), BigDecimal.ZERO));
        BigDecimal sysCulturalTax = t2.multiply(ObjectUtils.defaultIfNull(contractExcutionOrder.getDividedRate(), BigDecimal.ZERO))
                .multiply(new BigDecimal("0.015"))
                .divide(McnConstant.ONE_HUNDRED, 2, BigDecimal.ROUND_HALF_UP);
        if(needUpdate) {
            //更新系统参考计算分成&文建税
            calculationDevidedMapper.updateByNoStrategy(Wrappers.<CalculationDevided>lambdaUpdate()
                    .set(CalculationDevided::getSysDevidedAmount, sysDevidedAmount)
                    .set(CalculationDevided::getSysCulturalTax, sysCulturalTax)
                    .set(CalculationDevided::getUpdateBy, UserVoContextHolder.getUserId())
                    .set(CalculationDevided::getUpdateName, UserVoContextHolder.getUserName())
                    .set(CalculationDevided::getUpdateDate, new Date())
                    .eq(CalculationDevided::getExcutionOrderId, contractExcutionOrder.getId())
                    .eq(CalculationDevided::getIsDelete, NumberCst.ZERO));
        }
        return new DividedRateOrSysAmountVO(dividedRate, starContractDetail.getDividedRemark(), sysDevidedAmount, sysCulturalTax);
    }
}
